A Cursory Overview of The Rust Programming Language
A Cursory Overview of The Rust Programming Language
A Cursory Overview of The Rust Programming Language
http://rustbyexample.github.io/examples/hello/README.html
// hello.rs
// the main function
fn main() {
// print to the console
println!("Hello World!");
}
$ rustc hello.rs
$ ./hello
Hello World!
Contents
Introduction 1
1 Background 1
2 Design 2
2.1 Ownership . . . . . . . . . . . . . . . 2
2.2 Manual memory management . . . . 2
2.3 Type-system . . . . . . . . . . . . . 3
2.4 Concurrency . . . . . . . . . . . . . . 4
3 Influences 5
3.1 Functional elements . . . . . . . . . 5
3.2 Memory management . . . . . . . . 5
3.3 Concurrency . . . . . . . . . . . . . . 5
4 Use cases 6
4.1 Servo layout engine . . . . . . . . . . 6
4.2 Webrender . . . . . . . . . . . . . . . 6
4.3 Redox . . . . . . . . . . . . . . . . . 6
5 Benchmarks 6
6 Discussion 7
Programming Languages (Programspråk VT16), 7.5 hp 1(8)
• Minimal runtime. You can use Rust anywhere you could use C. There
are practical reasons why you may choose not to,
• Efficient C bindings. for example, there are not nearly as many libraries.
But Rust can work well with C libraries as it has
• Trait-based generics, this allows for Venn- efficient C-bindings, which are not the case with
diagram style implementations. how other languages, such as Java, call C code.
The same behaviour goes with functions. If we passManual memory management is possible thanks to
a variable as argument to a function, the functionthe ownership feature. Whenever a variable goes
will consume its ownership. This means that the out of scope, Rust frees the variable and all data it
code in Code snippet 2 also gives a compile-error.is bound to. This is the reason any data must be
owned by exactly one variable. It is quite easy to
fn main() {
see why. Suppose we have two variables owning the
let a = Box::new(23);
_
do something(a); // give away ownership
same data. If the first variable goes out of scope,
println!("The number is {}", a); // error both itself and the data it owned are automatically
} freed. Now, trying to use the second variable would
// i takes over ownership be very dangerous because it owns data that does
fn do_something(i: Box<i32>) { not exist anymore! This is why we would get a
// something is done here compile-error earlier in Code snippet 1. As a con-
} sequence from ownership, it is always safe to free
Code snippet 2: Functions take ownership of their related data when their variable goes out of scope.
passed arguments
Programming Languages (Programspråk VT16), 7.5 hp 3(8)
2.3 Type-system {
let x = box 5i;
In February 2015 Eric Reed at the University of Rust ensures that this free happens at the right
Washington proved the soundness and correctness time, when it is truly not used. Use-after-free is
of the combined type-system in Rust, where it was not possible. Rust enforces that no other writeable
only previously known that its constituent parts pointers alias to this heap memory, which means
were sound but it remained unknown if they re- writing to an invalid pointer is not possible.
mained sound together, as well as proved that the
static compile time analyzer Borrow Checker is cor- Using boxes and references together is very com-
rect.[8] mon. For example:
Boxes are what’s called an affine type. This means fn add_one(x: &int) -> int {
that the Rust compiler, at compile time, determines *x + 1
when the box comes into and goes out of scope, and }
inserts the appropriate calls there. Furthermore,
boxes are a specific kind of affine type, known as a fn main() {
let x = box 5i;
region.
_
println!("{}", add one(&*x));
You don’t need to fully grok the theory of affine
}
types or regions to grok boxes, though. As a rough
approximation, you can treat this Rust code, which
demonstrates a box: In this case, Rust knows that x is being ’borrowed’
by the add_one() function, and since it’s only read-
ing the value, allows it.
Programming Languages (Programspråk VT16), 7.5 hp 4(8)
Meanwhile regions pertain to the life-time of ob- communicate. By declaring a sender and receiver
jects, with respect to their scope. an expensive and time consuming task can be done
on a separate thread. When the task is completed
We can borrow x multiple times, as long as it’s not the result can be fetched from the receiver.
simultaneous:
What if you want to use many threads to work
fn add_one(x: &int) -> int { together on the same task? Rust has familiar syn-
*x + 1 chronization tools. A lock/mutex can contain a re-
}
source in order to allow several threads to use it
safely. Even if the idea of locks is similar to C they
fn main() {
let x = box 5i;
are not exactly the same. In C there is no explicit
relation between the lock and its contents, the lock
println!("{}", add_one(&*x)); only controls one or several blocks of code. In Rust
println!("{}", add_one(&*x)); mutex is a generic (i.e. Mutex<Type>) which di-
println!("{}", add_one(&*x)); rectly contains data.
}
“Lock data, not code” is enforced in
Rust.[9]
Or as long as it’s not a mutable borrow. This will
error during compile-time: Rust still does not allow more than one reference
to an object. How can the lock be shared between
fn add_one(x: &mut int) -> int { threads? Arc (Atomic Reference Counter) is an-
*x + 1 other generic that exists to solve this problem. An
}
Arc lets references be cloned and shared with new
owners. In general reference counters are a way to
fn main() {
let x = box 5i;
handle multiple references to the same data while
avoiding "use after free". No owner may directly
//err: cannot borrow immutable dereference deallocate the resource, instead the deallocation
//of ‘&‘-pointer as mutable will take place when the Arc determines that no
println!("{}", add_one(&*x)); references still exist (i.e. all owners have gone out
} of scope). Figure 1 on page 4 visualizes how a ref-
erence counter works. In order to share a mutable
resource an Arc can wrap a mutex which in turn
Notice we changed the signature of add_one() to
wraps a resource.
request a mutable reference.
2.4 Concurrency
These features are not embedded in the language uses of references and smart pointers.
itself, instead they are implemented in libraries. In
order to make them easier to replace updates or Rust also implements Resourse Acquisition Is Ini-
changes does not require a language update. tialization (RAII), a powerful concept that binds
the lifetime of a resource to the scope of the variable
Reference counters (as well as mutex etc) are not holding it[11]. Taken from C++, this gives safer
unique to Rust. However the programmer is en- memory management as destructors takes care of
couraged to write safe programs as Rust will not deallocation implicitly when leaving a function.
allow faulty code to compile. In other words: what
is considered good practice in other languages is In order to compete with C++ in terms of speed,
required in Rust. monomorphization is implemented in Rust [12]. It
allows for generic functions but compiles these to
specialized versions depending of how the function
is used in the code (e.g. one version handling int’s,
3 Influences one handling floats) and in C++ this is seen as
templates.
As expected, Rust draws its inspiration from many
While C++ is the raw model for memory manage-
other programming languages [10]. As Rust is
ment, ML Kit and Cyclone have provided the re-
truly a multiparadigm language, both supporting a
gion based memory management aspect of Rust.
pure-functional and object orientated approaches,
Region based memory management is used to be
the sources are widely spread over the spectrum of
able to do static verification of the lifetimes of ref-
paradigms.
erences, removing any runtime overhead and thus
It will be apparent from the following sections that improving speed performance.
Rust looks to other languages with focus on e.g.
However, what is interesting is that this is not tra-
concurrency to design its own version of concur-
ditional as it is combined with the scope-based re-
rency. In other words, Rust avoids to reinvent the
source management, but is used to prevent dangling
wheel as much as it can.
pointers.
50
Rust: rustc 1.6.0 (c30b771ad 2016-01-19)
6 Discussion
C gcc: gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
40 C++ g++: g++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
Because of some special features in Rust, such as
ownership, the learning curve is steeper than many
30 other languages. A beginner programmer will con-
stantly get compile-errors due to the strict rules
the code has to follow. This can cause some con-
20
fusion because the programmer initially believes to
have written correct code. On the other hand, this
10 is positive since it forces the programmer to think
more logically than they would have to in many
0
other languages. Also, Rust has a very friendly
ta t a ts y community that is willing to help out if some-
e
fas otid elbro x-dn idigi -tree
s nt ux -bod orm edux
le e p me red n l-n -r body gets stuck.[7] Having many people engaged in
e uc man
d
r eg i nary mple uch- c tra fasta
k-n b -co n k pe
e f a n s a fairly hard-to-learn programming language and
er s
rev
helping others out is important to make it grow
bigger. However, Rust is still a very new and small
Figure 2: Runtimes of each language as stacked
language. Over time or as it grows, it is possi-
bars to compare relative run-time
ble that the community loses this special advantage
simply because more Rust-related questions means
more work answering them.
Rust: rustc 1.6.0 (c30b771ad 2016-01-19)
20
C gcc: gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010 A bigger question mark, however, is how well Rust
C++ g++: g++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010
Mean Rust runtime performs against other languages that also aim at
Mean C runtime
Mean C++ runtime
being both fast and safe. Having the best perfor-
15 mance would be a big advantage to gain popularity
among programmers, and this could very well be
10
the case considering how close Rust already is to
C/C++ in this aspect.
0
ta e rot a ts es ux od
y x
fas tid elb gex-
dn igi tre en
t
ed
rm du
leo nd pid ry- lem ch-r n-b al-no ta-re
e uc a r e n a p u c tr a s
k-n
m bi om nnk sp
e f
e-c fa
ers
rev