---
title: Tech Lunch - Intro à Rust
author: Orestis Malaspinas
date: 11 janvier 2019
sansfont: Sans Serif
pdfMaxPagesPerSlide: 
	1
<!-- slide-numbers: true -->
---
# Historique

## Une brève histoire du Rust

- Créé comme projet personnel par Graydon Hoare chez Mozilla en 2006.
- Financé par Mozilla dès 2010.
- Rendu public la première fois en 2012 (version 0.4).
- Première version stable (1.0) en 2015.
- Stabilisation de fonctionnalités tous les 6 semaines.
- Version stable actuelle 1.31.1 <!-- TODO UPDATE -->

## Un développement pragmatique

- La très grande majorité des fonctionnalités originelles ont été retirées.
- Développement du langage orienté sur la communauté: *Request For Comments*.
- Langage système et de haut niveau: *Memory safety & concurrency without fear*.

# Projets basés sur Rust

- Firefox:
	* Servo (moteur parallèle de navigateur en collaboration avec Samsung)
	* Quantum (Moteur du navigateur de Firefox)
- Gnome (en remplacement du C).
- Dropbox.
- Npm.
- Cargo.
- Tor (en phase de tests).
- Redox (microkernel).

. . .

*<https://www.rust-lang.org/en-US/friends.html>*

# Concepts de base

## Généralités

- Des garanties de sûreté
	- Pas de seg-faults.
	- Pas d'accès concurrents.
	- Un système de type expressif.
. . .
- Sans coût de performance
	- Pas de garbage collector.
	- Pas d'overhead à l'exécution.

. . .

**Un langage "système" dans lequel on peut avoir confiance.**

- Productif: développement rapide, et exécution efficace.
- Projets "plus simples" à maintenir.

. . .

*Zero-cost abstractions & memory safety & data-race free* 
<!-- Productivité: efficacité et maintenance "simple". -->

# (Non-)sûreté mémoire

## Performance: un peu de C++

:::::::::::::: {.columns}
::: {.column width="50%"}
```
{
	vector<string> v; // alloué sur la pile
					  // et l'espace est
					  // contigu en mémoire
	...
	auto& elem = v[0]; // référence
	...
} // destruction automatique
```
:::
::: {.column width="50%"}
![](figs/mem_vec_str.svg){#fig:mem_vec_str width=80%}
:::
::::::::::::::

## Et la sûreté dans tout ça?

:::::::::::::: {.columns}
::: {.column width="50%"}
```
{
	vector<string> v; // alloué sur la pile
					  // et l'espace est
					  // contigu en mémoire
	...
	auto& elem = v[0]; // référence
	v.push_back(a_string);
	cout << elem;
	...
} // destruction automatique
```
:::
::: {.column width="50%"}
![](figs/mem_vec_str_error.svg){#fig:mem_vec_str width=80%}
:::
::::::::::::::

. . .

Quel est le problème dans ce code?

. . .

**`elem` est un pointeur pendouillant!**

## D'où provient le problème?

- Deux contraintes doivent être satisfaites en même temps
	1. Aliasing à l'élément 0 de `vector`.
	2. Modification de `vector` (désalloué et réalloué ailleurs).

- Simple de suivre *une* référence, difficile de les mettre à jour toutes.

# Sûreté mémoire en Rust

- En Rust, la sûreté en mémoire est garantie **à la compilation**.
- Il existe trois façons de posséder des données.

# Owned data

## Owner

- Quand on est **propriétaire** des données, on peut faire ce qu'on veut avec:
	1. Les lire.
	2. Les modifier.
	3. Les donner à quelqu'un d'autre.

## Owner (2/2)

![Comme avec un cahier. Source [Wikipedia](https://upload.wikimedia.org/wikipedia/commons/9/9f/Se%C5%A1ity.JPG)](https://upload.wikimedia.org/wikipedia/commons/9/9f/Se%C5%A1ity.JPG){#fig:mem_vec_str width=50%}

## En pratique (1/3)

<pre><code data-trim="hljs rust" class="lang-rust">
    fn do_something(_notebook: Vec<&str>) { // _notebook prend l'ownership
    // Do something with the library
} // _notebook est détruit et ses données aussi

fn main() {
    let mut notebook = Vec::new(); // par défaut notebook est immutable

    notebook.push("Il fait beau.");
    notebook.push("Les oiseaux chantent.");

    do_something(notebook); // ownership transféré à do_something
    do_something(notebook); // ici notebook ne possède plus ses données
							// => erreur de compilation!
}
</code></pre>

. . .

Le transfert de l'ownership est complètement décidé à la **compilation**.

## En pratique (2/3)

Ce qui se passe en mémoire:

![](figs/mem_vec_ownership.svg){#fig:mem_vec_ownership width=45%}![](figs/mem_vec_ownership_move.svg){#fig:mem_vec_ownership_move width=45%}

![](figs/mem_vec_ownership_dest.svg){#fig:mem_vec_ownership_move width=45%}

. . .

**`notebook` est détruit à la fin de `do_something` et ne peut plus être réutilisé**

## En pratique (3/3)

En C++ une sytaxe similaire a un effet complètement différent

```
void do_something(notebook: vector<string>) {
    // Do something with the notebook
} // la variable locale notebook est détruite et ses données aussi
  // le notebook du main existe toujours

void main() {
    vector<string> notebook; // par défaut notebook est mutable

    notebook.push_back("Il fait beau.");
    notebook.push_back("Les oiseaux chantent.");

    do_something(notebook); // le copy-constructeur de notebook 
							// est invoqué
    do_something(notebook); // on peut réutiliser notebook sans problème
}
```

# Shared reference

## Emprunt immutable (1/2)

Mais comment lire (ou modifier) le notebook et le réutiliser ensuite?

<pre><code data-trim="hljs rust" class="lang-rust">
    fn do_something(_notebook: Vec<&str>) -> Vec<&str> { // _notebook prend l'ownership
    // Do something with the library
	notebook
} // _notebook est détruit et ses données aussi

fn main() {
    let mut notebook = Vec::new(); // par défaut notebook est immutable

    notebook.push("Il fait beau.");
    notebook.push("Les oiseaux chantent.");

    notebook = do_something(notebook); // ownership transféré à do_something et on le retourne
    notebook = do_something(notebook); // on peut le réutiliser
}
</code></pre>

. . .

"Un peu" verbeux de faire comme cela.

## Emprunt immutable (2/2)

Solution: le propriétaire **prête** ses données.

1. On crée une référence vers les données (par défaut immutable).
2. On peut donner la référence.
3. Quand la référence sort de la portée elle est détruite, mais comme elle possède pas les données l'ownership est rendu aussi.

<pre><code data-trim="hljs rust" class="lang-rust">
	fn borrow(_notebook: &Vec<&str>) { // _notebook prend l'ownership de la référence vers un Vec
    // on peut lire les données contenues dans notebook
} // la référence est détruite, les données sont rendues à notebook

fn main() {
    let mut notebook = Vec::new(); // par défaut notebook est immutable

    notebook.push("Il fait beau.");
    notebook.push("Les oiseaux chantent.");

    borrow(& notebook); // on crée une référence et on la passe à borrow
    borrow(& notebook); // on peut réutiliser notebook
}
</code></pre>

## En pratique (1/2)

Ce qui se passe en mémoire:

![](figs/mem_vec_borrowing.svg){#fig:mem_vec_borrowing width=45%}![](figs/mem_vec_borrowing_end.svg){#fig:mem_vec_borrowing_end width=45%}

### Attention: un emprunt est **immutable** par définition!

## En pratique (2/2)

### Que se passe-t-il 

:::::::::::::: {.columns}
::: {.column width="50%"}
```
{
	vector<string> v; // alloué sur la pile
					  // et l'espace est
					  // contigu en mémoire
	...
	auto& elem = v[0]; // référence
	v.push_back(a_string);
	cout << elem;
	...
} // destruction automatique
```
:::
::: {.column width="50%"}
<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let mut v = Vec::new();
	v.push("Test.");

	let elem = &v[0]; // référence
	v.push("Test again.");
}
</code></pre>
:::
::::::::::::::

# Mutable reference

## Emprunt mutable

Le propriétaire **prête** ses données mais l'emprunteur peut les modifier.

1. On crée une **mutable** référence vers les données (on peut les modifier).
2. On peut donner la référence.
3. Quand la référence sort de la portée elle est détruite, mais comme elle possède pas les données l'ownership est rendu aussi.

. . .

<pre><code data-trim="hljs rust" class="lang-rust">
	fn mut_borrow(notebook: &mut Vec<&str>) { // _notebook prend l'ownership de la référence vers un Vec
		notebook.push("On peut modifier les données");
    // on peut lire les données contenues dans notebook et les modifier
} // la référence est détruite, les données sont rendues à notebook

fn main() {
    let mut notebook = Vec::new(); // par défaut notebook est immutable

    notebook.push("Il fait beau.");
    notebook.push("Les oiseaux chantent.");

    mut_borrow(&mut notebook); // on crée une référence et on la passe à borrow
    mut_borrow(&mut notebook); // on peut réutiliser notebook
}
</code></pre>

## En pratique (1/2)

![](figs/mem_vec_mut_borrowing.svg){#fig:mem_vec_borrowing width=70%}

La référence est **vérouillée** personne d'autre ne peut modifier ou lire les données.

## En pratique (2/2)

<pre><code data-trim="hljs rust" class="lang-rust">
fn main() {
    let mut notebook = Vec::new(); // par défaut notebook est immutable

    notebook.push("Il fait beau.");
    notebook.push("Les oiseaux chantent.");

    {
		let mut_borrow = &mut notebook;
		notebook.len(); // only mut_borrow can read or write.

		mut_borrow.push("Je le peux.");
	} // mutable borrow ends here

	notebook.push("Je le peux aussi à présent.");

}
</code></pre>

# Les lois de Rust

## Les trois loi de la propriété

1. Chaque valeur a une variable qui est son propriétaire (`owner`).
2. Une valeur ne peut avoir qu'un seul propriétaire à chaque instant.
3. Quand le programme sort de la portée du propriétaire, la valeur est détruite (`dropped`).

## Les deux lois de l'emprunt

1. On peut avoir autant de références **immutables** qu'on le shoutaire sur des données.
2. On ne peut avoir **une seule** référence mutable sur des données.

# `Unsafe` Rust

## Toute règle est faite pour être contournée

- Dans des cas particuliers, on doit pouvoir manipuler la mémoire de façon "dangereuse".
- Avec de grands privilèges viennent de grandes responsabilités: on doit pouvoir localiser **facilement** ces endroits dangereux.
- En bon Rust ils doivent être rares (4% du code de `rustc`).
- Exemple : `raw pointer`



# And many more

- Error handling: `Option`, `Result`.
- Tests.
- Benchmarks (`nightly only`).
- *Hygienic* macros!.
- Cargo.
- `crates.io`
