rust: modern, practical, safe, fast programming...

49
Rust: modern, practical, safe, fast programming language Stepan Koltsov <[email protected]> C++ Party, Minsk

Upload: others

Post on 26-Jan-2021

6 views

Category:

Documents


1 download

TRANSCRIPT

  • Rust: modern, practical, safe, fast programming language

    Stepan Koltsov

    C++ Party, Minsk

    mailto:[email protected]

  • 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 = range(2u, 10000u) .filter(|&n| is_prime(n)).collect();

    Functional

  • 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::string error; uint cached; }}

    enum (tagged union)

  • fn create_server(conf: Conf) { … }!

    fn main() { let conf = Conf { … } create_server(conf); // compile-time error: `conf` is moved println!("{}", conf);}

    Everything is moved

  • fn create_server(conf: Conf) { … }!

    fn main() { let conf = Conf { … } // pass a copy, keep the original create_server(conf.clone()); println!("{}", conf);}

    Clone trait

  • Vec; &[T]; String, &str

    C++ Rust

    std::vector std::Vec

    std::array_view &[T]

    std::string std::String

    std::string_view &str

  • // C++ llvm::ArrayRef; Rust &[T]struct Slice { T* begin; T* end;}!

    // C++ string_view; Rust: &strtype StrSlice = Slice;

    What is Slice

  • // similar to std::vectorlet v1: Vec = vec!(10, 20, 30);!

    // Slice, similar to std::array_viewlet v2: &[uint] = v1.as_slice();!

    // another slicelet v3 = v2.slice_from(1);!

    // prints [20, 30]println!("{}", v3.to_str());

    Vec

  • fn sum(ns: &[T]) -> T { let sum = T::zero(); for n in ns { sum += n; } n}!

    fn sum(ns: &[T]) -> T { … }!

    sum(&[1, 2]); //

  • 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 colon = url.find(':'); return url.substr(0, colon);}!int main() { auto scheme = get_scheme_from_url(get_url()); std::cout

  • fn get_url() -> String { "http://yandex.ru".to_string()}!fn get_scheme_from_url &'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

  • struct UrlParts UrlParts

  • enum MaybeOwned MaybeOwned

  • impl &'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

  • struct Person { name: String,}!impl &'s str { if name.empty() { "unnamed" // &'static str } else { self.name.as_slice() } }}

    Static Lifetime

  • fn longest_str b.len() { a } else { b }}!

    fn foo &'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

  • void foo(vector& xs) { typedef vector::iterator iter; for (iter i = xs.begin(); i != xs.end(); ++i) { if (*i == 0) { xs.push_back(1); } }}

    Mutability: C++

  • fn foo(xs: &mut Vec) { 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 at a timetmp2.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 endstmp2.rs:3 let b = &mut a; ^tmp2.rs:5:2: 5:2 note: previous borrow ends here

    Cannot borrow as mutable twice

  • 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 borrowedmut.rs:5 a = 3; ^mut.rs:4:13: 4:15 note: borrow of `a` occurs heremut.rs:4 let b = &a; ^~

    Cannot assign, because borrowed

  • Smart Pointers

    C++ Rust

    std::unique_ptr Box

    std::shared_ptr Rc or Arc

  • struct Foo { v: int,}!

    let ptr = Rc::new(Foo { … });println!("{}", ptr.v);

    User-defined pointers: Rc

  • struct RcBox { value: T, ref_count: uint,}!

    pub struct Rc { // unsafe pointer ptr: *mut RcBox,}!

    impl Deref for Rc { fn deref(&'a self) -> &'a T { … }}

    Rc 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 than once task::spawn(proc() { println!("{}", i); });}

    Tasks

  • 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

  • // similar to Rc except// Arc uses atomic counter, not plain// data is immutable inside Arc// so Arc can be safely shared between threadslet 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

  • Mutex

    • Mutex = T + mutex • Safely share data between threads

  • fn do_smth(shared_data: Arc) { // 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

  • 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 = vec!(1, 2, 3); unsafe { memset(v.as_mut_ptr(), 10, v.len()); } println!("{}", v.to_str());}

    unsafe

  • 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 next(self) -> uint { self + 1 }}!fn print_first_10_naturals() { let mut i: T = Natural::zero(); for _ in range(0, 10) { println!("{}", i.to_str()); i = i.next(); }}

    Type classes (traits)

  • 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

  • fn print_anything(xs: &[Box]) { for x in xs.iter() { println!("{}", x.to_str()); }}!

    fn main() { let mut v: Vec = Vec::new(); v.push(box 1 as Box); v.push(box true as Box); print_anything(v.as_slice());}

    Templates: dynamic dispatching

  • class FileInputStream: public InputStream { int fd;}!

    // is actually!

    struct FileInputStream { void* vtablePtr; int fd;}

    C++ vtable

  • 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

  • Fin

    Stepan Koltsov

    mailto:[email protected]