Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Rust: modern, practical, safe, fast
programming language
Stepan Koltsov <nga@yandex-team.ru>
Java Party, Kyiv
Why Rust
• Java
• Safe*
• … at a price of CPU/mem overhead
• C++
• Very fast
• Very low memory overhead
• Unsafe
• Rust
• ...
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 {	
ipAddr: IpAddr,	
port: uint,	
}
struct
enum CacheStatus {	
Error(String),	
Cached(uint),	
}	
!
// Haskell	
!
data CacheStatus = Error String | Cached Int	
!
// C...
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>; &[T]; String, &str
Java Java C++ Rust
ArrayList<T> IntBuffer std::vector<T> std::Vec<T>
.subList() .slice() std::a...
// C++ std::array_view<T>; Rust &[T]	
struct Slice<T> {	
T* begin;	
T* end;	
}	
!
// C++ std::string_view; Rust: &str	
typ...
// similar to std::vector	
let v1: Vec<uint> = vec!(10, 20, 30);	
!
// Slice, similar to std::array_view	
let v2: &[uint] ...
fn sum<T : Num>(ns: &[T]) -> T {	
let sum = T::zero();	
for n in ns { sum += n; }	
sum	
}
traits (type classes)
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 common_prefix<'s>(a: &'s str, b: &'s str)	
-> &'s str	
{ … }	
!
fn foo<'a>(a: &'a str) -> &'a str {	
let b = "bb".to_st...
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();	
!
// do smth w...
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: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов
Upcoming SlideShare
Loading in …5
×

Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов

2,597 views

Published on

Последние 15 лет между разработчиками на Java и на C++ ведётся спор о том, какой язык программирования хуже — Java или C++. Программы на C++ глючат, падают, и в них утекает память. Программы на Java тормозят и требуют слишком много памяти.

Rust — новый язык программирования, разрабатываемый компанией Mozilla — решает проблемы Java и C++: программы, написанные на Rust, одновременно быстрые и безопасные. Rust является таким же низкоуровневым, close-to-metal языком программирования, как и C++, однако в язык встроены конструкции, позволяющие на этапе компиляции доказывать, что в программе не случится обращения к неинициализированной памяти (механизм borrowed pointers). Большая часть моего рассказа будет посвящена описанию этого механизма.

Published in: Technology
  • Be the first to comment

Rust: код может быть одновременно безопасным и быстрым, Степан Кольцов

  1. 1. Rust: modern, practical, safe, fast programming language Stepan Koltsov <nga@yandex-team.ru> Java Party, Kyiv
  2. 2. Why Rust • Java • Safe* • … at a price of CPU/mem overhead • C++ • Very fast • Very low memory overhead • Unsafe • Rust • As fast as C++*, safer then Java
  3. 3. Basic examples
  4. 4. fn main() { println!("hello world"); } Hello world
  5. 5. 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
  6. 6. Data types • primitives: bool, int, u32, f32, etc. • builtins: &[], &str • user-defined: struct, enum, trait • functions
  7. 7. struct SocketAddr { ipAddr: IpAddr, port: uint, } struct
  8. 8. enum CacheStatus { Error(String), Cached(uint), } ! // Haskell ! data CacheStatus = Error String | Cached Int ! // C++ ! struct CacheStatus { unsigned tag; union { std::string error; uint cached; } } ! // Java ! abstract class CacheStatus {} class Error { … } class Cached { … } enum (tagged union)
  9. 9. fn create_server(conf: Conf) { … } ! fn main() { let conf = Conf { … } create_server(conf); // compile-time error: `conf` is moved println!("{}", conf); } Everything is moved
  10. 10. fn create_server(conf: Conf) { … } ! fn main() { let conf = Conf { … } // pass a copy, keep the original create_server(conf.clone()); println!("{}", conf); } Clone trait
  11. 11. Vec<T>; &[T]; String, &str Java Java C++ Rust ArrayList<T> IntBuffer std::vector<T> std::Vec<T> .subList() .slice() std::array_view &[T] StringBuffer std::string std::String - std::string_view &str
  12. 12. // C++ std::array_view<T>; Rust &[T] struct Slice<T> { T* begin; T* end; } ! // C++ std::string_view; Rust: &str type StrSlice = Slice<char>; What is slice
  13. 13. // 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
  14. 14. fn sum<T : Num>(ns: &[T]) -> T { let sum = T::zero(); for n in ns { sum += n; } sum } traits (type classes)
  15. 15. Pointers • raw unsafe pointers *Foo • borrowed pointers &Foo • smart pointers
  16. 16. 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
  17. 17. 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() { // compile-time error let scheme2 = get_scheme_from_url(get_url().as_slice()); ! // works let url = get_url(); let scheme = get_scheme_from_url(url.as_slice()); println!("{}", scheme); } Same in Rust
  18. 18. 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
  19. 19. enum MaybeOwned<'a> { Slice(&'a str), Owned(String), } ! fn from_utf8_lossy<'a>(v: &'a [u8]) -> MaybeOwned<'a> { … } MaybeOwned
  20. 20. 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
  21. 21. 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
  22. 22. fn common_prefix<'s>(a: &'s str, b: &'s str) -> &'s str { … } ! 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; // error } Lifetime intersection
  23. 23. void foo(vector<int>& xs) { typedef vector<int>::iterator iter; for (iter i = xs.begin(); i != xs.end(); ++i) { if (*i == 0) { // modCount in Java xs.push_back(1); } } } Mutability: C++
  24. 24. fn foo(xs: &mut Vec<int>) { for p in xs.iter() { if *p == 0 { xs.push(1); } } } Mutability: Rust
  25. 25. 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
  26. 26. 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
  27. 27. Smart Pointers C++ Rust std::unique_ptr<T> Box<T> std::shared_ptr<T> Rc<T> or Arc<T>
  28. 28. struct Foo { v: int, } ! let ptr = Rc::new(Foo { … }); println!("{}", ptr.v); User-defined pointers: Rc<T>
  29. 29. 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
  30. 30. Threads • tasks • channels • Arc • AtomicInt • Mutex
  31. 31. 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
  32. 32. 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
  33. 33. // 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>
  34. 34. Mutex<T> • Mutex<T> = T + mutex • Safely share data between threads
  35. 35. fn do_smth(shared_data: Arc<Mutex<T>>) { // guard + smart pointer let ptr_and_lock = shared_data.lock(); ! // do smth with guarded object ptr_and_lock.foo_bar(); ! // ptr_and_lock destructor is called // and the end of the fn, // lock is released } Mutex<T>
  36. 36. 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
  37. 37. Program performance 0 25 50 75 100 Performance of compiled code C++ Rust Java
  38. 38. Program safety 0 25 50 75 100 Performance of compiled code C++ Rust Java
  39. 39. Development speed 0 25 50 75 100 Speed of development C++ Rust Java
  40. 40. Problems • compile-time metaprogramming • IDE • incremental compilation
  41. 41. 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)
  42. 42. 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
  43. 43. 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
  44. 44. class FileInputStream: public InputStream { int fd; } ! // is actually ! struct FileInputStream { void* vtablePtr; int fd; } C++/Java vtable
  45. 45. 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
  46. 46. Fin Stepan Koltsov <nga@yandex-team.ru>

×