• Like
Степан Кольцов — Rust — лучше, чем C++
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

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

  • 3,383 views
Published

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

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

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

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

Published in Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
3,383
On SlideShare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
10
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Rust: modern, practical, safe, fast programming language Stepan Koltsov <nga@yandex-team.ru> C++ Party, Minsk
  • 2. Basic examples
  • 3. fn main() { println!("hello world"); } Hello world
  • 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. Data types • primitives: bool, int, u32, f32, etc. • builtins: &[], &str • user-defined: struct, enum, trait • functions
  • 6. struct SocketAddr { host: String, port: uint, } struct
  • 7. enum CacheStatus { Error(String), Cached(uint), } ! // C++ ! struct CacheStatus { unsigned tag; union { std::string error; uint cached; } } enum (tagged union)
  • 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. 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. 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. // 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. // 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. 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. Pointers • raw unsafe pointers *Foo • borrowed pointers &Foo • smart pointers
  • 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. 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. 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. enum MaybeOwned<'a> { Slice(&'a str), Owned(String), } ! fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> { … } MaybeOwned
  • 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. 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. 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. 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. fn foo(xs: &mut Vec<int>) { for p in xs.iter() { if *p == 0 { xs.push(1); } } } Mutability: Rust
  • 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. 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. Smart Pointers C++ Rust std::unique_ptr<T> Box<T> std::shared_ptr<T> Rc<T> or Arc<T>
  • 27. struct Foo { v: int, } ! let ptr = Rc::new(Foo { … }); println!("{}", ptr.v); User-defined pointers: Rc<T>
  • 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. Threads • tasks • channels • Arc • AtomicInt • Mutex
  • 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. 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. // 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. Mutex<T> • Mutex<T> = T + mutex • Safely share data between threads
  • 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. 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. Program performance 0 25 50 75 100 Performance of compiled code C++ Rust Java
  • 37. Program safety 0 25 50 75 100 Performance of compiled code C++ Rust Java
  • 38. Development speed 0 25 50 75 100 Speed of development C++ Rust Java
  • 39. Problems • compile-time metaprogramming • IDE • incremental compilation
  • 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. 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. 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. class FileInputStream: public InputStream { int fd; } ! // is actually ! struct FileInputStream { void* vtablePtr; int fd; } C++ vtable
  • 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. Fin Stepan Koltsov <nga@yandex-team.ru>