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

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

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

3,458
views

Published on

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

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

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

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

Published in: Technology

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
3,458
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
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>