Rust: modern, practical, safe, fast
programming language
Stepan Koltsov <nga@yandex-team.ru>
C++ Party, Minsk
Basic examples
fn main() {	
println!("hello world");	
}
Hello world
fn is_prime(n: uint) -> bool {	
range(2, n).all(|x| n % x != 0) // lambda	
}	
!
let primes: Vec<uint> = range(2u, 10000u)	...
Data types
• primitives: bool, int, u32, f32, etc.
• builtins: &[], &str
• user-defined: struct, enum, trait
• functions
struct SocketAddr {	
host: String,	
port: uint,	
}
struct
enum CacheStatus {	
Error(String),	
Cached(uint),	
}	
!
// C++	
!
struct CacheStatus {	
unsigned tag;	
union {	
std::strin...
fn create_server(conf: Conf) { … }	
!
fn main() {	
let conf = Conf { … }	
create_server(conf);	
// compile-time error: `co...
fn create_server(conf: Conf) { … }	
!
fn main() {	
let conf = Conf { … }	
// pass a copy, keep the original	
create_server...
Vec; &[T]; String, &str
C++ Rust
std::vector<T> std::Vec<T>
std::array_view &[T]
std::string std::String
std::string_view ...
// C++ llvm::ArrayRef<T>; Rust &[T]	
struct Slice<T> {	
T* begin;	
T* end;	
}	
!
// C++ string_view; Rust: &str	
type StrS...
// similar to std::vector	
let v1: Vec<uint> = vec!(10, 20, 30);	
!
// Slice, similar to std::array_view	
let v2: &[uint] ...
fn sum<T>(ns: &[T]) -> T {	
let sum = T::zero();	
for n in ns { sum += n; }	
n	
}	
!
fn sum<T : Num>(ns: &[T]) -> T { … }	...
Pointers
• raw unsafe pointers *Foo
• borrowed pointers &Foo
• smart pointers
std::string get_url() {	
return "http://yandex.ru";	
}	
!
string_view get_scheme_from_url(string_view url) {	
unsigned col...
fn get_url() -> String {	
"http://yandex.ru".to_string()	
}	
!
fn get_scheme_from_url<'s>(url: &'s str) -> &'s str {	
let ...
struct UrlParts<'a> {	
scheme: &'a str,	
host: &'a str,	
port: uint,	
path: &'a str,	
}	
!
fn parse_url<'a>(url: &'a str)	...
enum MaybeOwned<'a> {	
Slice(&'a str),	
Owned(String),	
}	
!
fn from_utf8_lossy<'a>(v: &'a [u8])	
-> MaybeOwned<'a>	
{ … }...
impl<'s> MaybeOwned {	
fn as_slice(&'s self) -> &'s str {	
match self {	
Owned(ref s) => s.as_slice(),	
Slice(s) => s,	
}	...
struct Person {	
name: String,	
}	
!
impl<'s> Person {	
fn get_name_or_default(&'s self) -> &'s str {	
if name.empty() {	
...
fn longest_str<'s>(a: &'s str, b: &'s str)	
-> &'s str	
{	
if a.len() > b.len() { a } else { b }	
}	
!
fn foo<'a>(a: &'a s...
void foo(vector<int>& xs) {	
typedef vector<int>::iterator iter;	
for (iter i = xs.begin(); i != xs.end(); ++i)	
{	
if (*i...
fn foo(xs: &mut Vec<int>) {	
for p in xs.iter() {	
if *p == 0 {	
xs.push(1);	
}	
}	
}
Mutability: Rust
let mut a = 1;	
let b = &mut a;	
let c = &mut a;	
!
tmp2.rs:4:18: 4:19 error: cannot borrow `a` as
mutable more than once ...
let mut a = 1;	
a = 2;	
let b = &a;	
a = 3;	
!
!
mut.rs:5:5: 5:6 error: cannot assign to `a`
because it is borrowed	
mut.r...
Smart Pointers
C++ Rust
std::unique_ptr<T> Box<T>
std::shared_ptr<T> Rc<T> or Arc<T>
struct Foo {	
v: int,	
}	
!
let ptr = Rc::new(Foo { … });	
println!("{}", ptr.v);
User-defined pointers: Rc<T>
struct RcBox<T> {	
value: T,	
ref_count: uint,	
}	
!
pub struct Rc<T> {	
// unsafe pointer	
ptr: *mut RcBox<T>,	
}	
!
impl...
Threads
• tasks
• channels
• Arc
• AtomicInt
• Mutex
for i in range(0, 100) {	
// proc is a keyword	
// proc closure can be passed btw threads	
// and may be called no more th...
let (sender, receiver) = channel();	
!
for i in range(0, 100) {	
let sender_for_task = sender.clone();	
task::spawn(proc()...
// similar to Rc<T> except	
// Arc uses atomic counter, not plain	
// data is immutable inside Arc	
// so Arc can be safel...
Mutex<T>
• Mutex<T> = T + mutex
• Safely share data between threads
fn do_smth(shared_data: Arc<Mutex<T>>) {	
// guard + smart pointer	
let ptr_and_lock = shared_data.lock();	
ptr_and_lock.f...
unsafe fn memset(mem: *mut u8, c: u8, len: uint)	
{	
for i in range(0, len) {	
*mem.offset(i as int) = c;	
}	
}	
!
fn main...
Program performance
0
25
50
75
100
Performance of compiled code
C++ Rust Java
Program safety
0
25
50
75
100
Performance of compiled code
C++ Rust Java
Development speed
0
25
50
75
100
Speed of development
C++ Rust Java
Problems
• compile-time metaprogramming
• IDE
• incremental compilation
trait Natural {	
fn zero() -> Self;	
fn next(self) -> Self;	
}	
!
impl Natural for uint {	
fn zero() -> uint { 0 }	
fn nex...
macro_rules! vec(	
($($e:expr),*) => ({	
let mut _temp = ::std::vec::Vec::new();	
$(_temp.push($e);)*	
_temp	
})	
)	
!
let...
fn print_anything(xs: &[Box<ToStr>]) {	
for x in xs.iter() {	
println!("{}", x.to_str());	
}	
}	
!
fn main() {	
let mut v:...
class FileInputStream: public InputStream {	
int fd;	
}	
!
// is actually	
!
struct FileInputStream {	
void* vtablePtr;	
i...
struct FileInputStream {	
fd: int	
}	
!
impl InputStream for FileInputStream { … }	
!
let r: &FileInputStream = …	
let s: ...
Fin
Stepan Koltsov <nga@yandex-team.ru>
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Степан Кольцов — Rust — лучше, чем C++
Upcoming SlideShare
Loading in …5
×

Степан Кольцов — Rust — лучше, чем C++

4,075 views

Published on

Rust — это современный, практический, быстрый и безопасный язык программирования. Некоторые говорят, что Rust — это как C++, если бы его писал человек, знающий Haskell.

Система типов Rust решает главную проблему C++ — небезопасность. C++ очень легко сделать ошибки, которые приведут к поломкам (например, use after free). Rust позволяет писать безопасный код, сохраняя при этом выразительность и околонулевые накладные расходы C++. В докладе будут подробно описаны механизмы языка, которые контролируют безопасность программы.

Хотя в данный момент Rust ещё не подходит для использования в продакшне, его всё равно стоит изучать. Во-первых, потому что это очень интересный подход к программированию, а во-вторых, потому что через несколько лет для разработки требовательных к ресурсам программ будет необходим именно Rust или другой похожий инструмент.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,075
On SlideShare
0
From Embeds
0
Number of Embeds
2,558
Actions
Shares
0
Downloads
12
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Степан Кольцов — Rust — лучше, чем C++

  1. 1. Rust: modern, practical, safe, fast programming language Stepan Koltsov <nga@yandex-team.ru> C++ Party, Minsk
  2. 2. Basic examples
  3. 3. fn main() { println!("hello world"); } Hello world
  4. 4. fn is_prime(n: uint) -> bool { range(2, n).all(|x| n % x != 0) // lambda } ! let primes: Vec<uint> = range(2u, 10000u) .filter(|&n| is_prime(n)).collect(); Functional
  5. 5. Data types • primitives: bool, int, u32, f32, etc. • builtins: &[], &str • user-defined: struct, enum, trait • functions
  6. 6. struct SocketAddr { host: String, port: uint, } struct
  7. 7. enum CacheStatus { Error(String), Cached(uint), } ! // C++ ! struct CacheStatus { unsigned tag; union { std::string error; uint cached; } } enum (tagged union)
  8. 8. fn create_server(conf: Conf) { … } ! fn main() { let conf = Conf { … } create_server(conf); // compile-time error: `conf` is moved println!("{}", conf); } Everything is moved
  9. 9. fn create_server(conf: Conf) { … } ! fn main() { let conf = Conf { … } // pass a copy, keep the original create_server(conf.clone()); println!("{}", conf); } Clone trait
  10. 10. Vec; &[T]; String, &str C++ Rust std::vector<T> std::Vec<T> std::array_view &[T] std::string std::String std::string_view &str
  11. 11. // C++ llvm::ArrayRef<T>; Rust &[T] struct Slice<T> { T* begin; T* end; } ! // C++ string_view; Rust: &str type StrSlice = Slice<char>; What is Slice
  12. 12. // similar to std::vector let v1: Vec<uint> = vec!(10, 20, 30); ! // Slice, similar to std::array_view let v2: &[uint] = v1.as_slice(); ! // another slice let v3 = v2.slice_from(1); ! // prints [20, 30] println!("{}", v3.to_str()); Vec
  13. 13. fn sum<T>(ns: &[T]) -> T { let sum = T::zero(); for n in ns { sum += n; } n } ! fn sum<T : Num>(ns: &[T]) -> T { … } ! sum(&[1, 2]); // <- OK sum(&[true, false]); // <- error is here traits (type classes; concepts)
  14. 14. Pointers • raw unsafe pointers *Foo • borrowed pointers &Foo • smart pointers
  15. 15. std::string get_url() { return "http://yandex.ru"; } ! string_view get_scheme_from_url(string_view url) { unsigned colon = url.find(':'); return url.substr(0, colon); } ! int main() { auto scheme = get_scheme_from_url(get_url()); std::cout << scheme << "n"; return 0; } Motivating example
  16. 16. fn get_url() -> String { "http://yandex.ru".to_string() } ! fn get_scheme_from_url<'s>(url: &'s str) -> &'s str { let colon = url.find_str("://").unwrap(); url.slice_to(colon) } ! fn main() { let url = get_url(); let scheme = get_scheme_from_url(url.as_slice()); println!("{}", scheme); ! // compile-time error let scheme2 = get_scheme_from_url(get_url().as_slice()); } Same in Rust
  17. 17. struct UrlParts<'a> { scheme: &'a str, host: &'a str, port: uint, path: &'a str, } ! fn parse_url<'a>(url: &'a str) -> UrlParts<'a> { UrlParts { … } } More examples
  18. 18. enum MaybeOwned<'a> { Slice(&'a str), Owned(String), } ! fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> { … } MaybeOwned
  19. 19. impl<'s> MaybeOwned { fn as_slice(&'s self) -> &'s str { match self { Owned(ref s) => s.as_slice(), Slice(s) => s, } } ! fn into_string(self) -> String { match self { Owned(s) => s, Slice(s) => s.to_string(), } } } enum pattern matching
  20. 20. struct Person { name: String, } ! impl<'s> Person { fn get_name_or_default(&'s self) -> &'s str { if name.empty() { "unnamed" // &'static str } else { self.name.as_slice() } } } Static Lifetime
  21. 21. fn longest_str<'s>(a: &'s str, b: &'s str) -> &'s str { if a.len() > b.len() { a } else { b } } ! fn foo<'a>(a: &'a str) -> &'a str { let b = "bb".to_string(); // lifetime of c is intersection let c = longest_str( a.as_slice(), b.as_slice()); return c; } Lifetime intersection
  22. 22. void foo(vector<int>& xs) { typedef vector<int>::iterator iter; for (iter i = xs.begin(); i != xs.end(); ++i) { if (*i == 0) { xs.push_back(1); } } } Mutability: C++
  23. 23. fn foo(xs: &mut Vec<int>) { for p in xs.iter() { if *p == 0 { xs.push(1); } } } Mutability: Rust
  24. 24. let mut a = 1; let b = &mut a; let c = &mut a; ! tmp2.rs:4:18: 4:19 error: cannot borrow `a` as mutable more than once at a time tmp2.rs:4 let c = &mut a; ^ tmp2.rs:3:18: 3:19 note: previous borrow of `a` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `a` until the borrow ends tmp2.rs:3 let b = &mut a; ^ tmp2.rs:5:2: 5:2 note: previous borrow ends here Cannot borrow as mutable twice
  25. 25. let mut a = 1; a = 2; let b = &a; a = 3; ! ! mut.rs:5:5: 5:6 error: cannot assign to `a` because it is borrowed mut.rs:5 a = 3; ^ mut.rs:4:13: 4:15 note: borrow of `a` occurs here mut.rs:4 let b = &a; ^~ Cannot assign, because borrowed
  26. 26. Smart Pointers C++ Rust std::unique_ptr<T> Box<T> std::shared_ptr<T> Rc<T> or Arc<T>
  27. 27. struct Foo { v: int, } ! let ptr = Rc::new(Foo { … }); println!("{}", ptr.v); User-defined pointers: Rc<T>
  28. 28. struct RcBox<T> { value: T, ref_count: uint, } ! pub struct Rc<T> { // unsafe pointer ptr: *mut RcBox<T>, } ! impl<T> Deref<T> for Rc<T> { fn deref(&'a self) -> &'a T { … } } Rc impl
  29. 29. Threads • tasks • channels • Arc • AtomicInt • Mutex
  30. 30. for i in range(0, 100) { // proc is a keyword // proc closure can be passed btw threads // and may be called no more than once task::spawn(proc() { println!("{}", i); }); } Tasks
  31. 31. let (sender, receiver) = channel(); ! for i in range(0, 100) { let sender_for_task = sender.clone(); task::spawn(proc() { // do something sender_for_task.send(i * i); }); } ! for i in range(0, 100) { let r = receiver.recv(); println!("{}", r); } Channels
  32. 32. // similar to Rc<T> except // Arc uses atomic counter, not plain // data is immutable inside Arc // so Arc can be safely shared between threads let conf = Arc::new(ServerConf { … }); ! for i in range(0, 100) { // must get a copy of Arc // to pass it to another thread let conf_c = conf.clone(); task::spawn(proc() { println!("{}", conf_c); }); } Arc<T>
  33. 33. Mutex<T> • Mutex<T> = T + mutex • Safely share data between threads
  34. 34. fn do_smth(shared_data: Arc<Mutex<T>>) { // guard + smart pointer let ptr_and_lock = shared_data.lock(); ptr_and_lock.foo_bar(); ! // ptr_and_lock destructor is called // and the end of the fn, // lock is released } Mutex<T>
  35. 35. unsafe fn memset(mem: *mut u8, c: u8, len: uint) { for i in range(0, len) { *mem.offset(i as int) = c; } } ! fn main() { let mut v: Vec<u8> = vec!(1, 2, 3); unsafe { memset(v.as_mut_ptr(), 10, v.len()); } println!("{}", v.to_str()); } unsafe
  36. 36. Program performance 0 25 50 75 100 Performance of compiled code C++ Rust Java
  37. 37. Program safety 0 25 50 75 100 Performance of compiled code C++ Rust Java
  38. 38. Development speed 0 25 50 75 100 Speed of development C++ Rust Java
  39. 39. Problems • compile-time metaprogramming • IDE • incremental compilation
  40. 40. trait Natural { fn zero() -> Self; fn next(self) -> Self; } ! impl Natural for uint { fn zero() -> uint { 0 } fn next(self) -> uint { self + 1 } } ! fn print_first_10_naturals<T : Natural + ToStr>() { let mut i: T = Natural::zero(); for _ in range(0, 10) { println!("{}", i.to_str()); i = i.next(); } } Type classes (traits)
  41. 41. macro_rules! vec( ($($e:expr),*) => ({ let mut _temp = ::std::vec::Vec::new(); $(_temp.push($e);)* _temp }) ) ! let v = vec!(1, 2, if cond { 3 } else { 4 }); vec!(struct); // fails at parse time Macros
  42. 42. fn print_anything(xs: &[Box<ToStr>]) { for x in xs.iter() { println!("{}", x.to_str()); } } ! fn main() { let mut v: Vec<Box<ToStr>> = Vec::new(); v.push(box 1 as Box<ToStr>); v.push(box true as Box<ToStr>); print_anything(v.as_slice()); } Templates: dynamic dispatching
  43. 43. class FileInputStream: public InputStream { int fd; } ! // is actually ! struct FileInputStream { void* vtablePtr; int fd; } C++ vtable
  44. 44. struct FileInputStream { fd: int } ! impl InputStream for FileInputStream { … } ! let r: &FileInputStream = … let s: &InputStream = r as &InputStream; ! // is actually ! struct InputStream_Ptr { data: &InputStream, vtable: … } ! sizeof(r) == sizeof(void*) sizeof(s) == 2 * sizeof(void*) Rust vtable
  45. 45. Fin Stepan Koltsov <nga@yandex-team.ru>

×