Fraunhofer FOKUS Institut für Offene Kommunikationssysteme ...€¦ · Fraunhofer FOKUS Institut...

Post on 26-Jun-2020

1 views 0 download

transcript

Fraunhofer FOKUS

Institut für Offene Kommunikationssysteme

© M

ichael Z

ale

wski/ F

raunh

ofe

r FO

KU

S

ust and

Max Bureck | 25.10.2018 | EclipseCon Europe 2018

Fraunhofer FOKUS

Institute for Open Communication Systems

Alternative Agenda

1 Introduction

2 Data Types

3 Memory Management

4 Control Flow

5 Behavior for Data Types

6 IDE Story and Corrosion

7 Conclusion

| 25.10.2018 | Rust and Eclipse2

1 Introduction

2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018

* not as breaking as you might think

History and Development

| 25.10.2018 | Rust and Eclipse4

Started as hobby

project by Mozilla

employee

Graydon Hoare

First stable

version 1.0

The new

“2018 Edition”

with breaking

changes* will

be introduced

Since then new

stable release

every 6 weeks

Mozilla started

sponsoring the

project

Mozilla started

using Rust for

experimental

browser engine

Servo

Rust considers itself a “systems programming language”

Compiled to native code (compiler is LLVM frontend)

Motto: safe, fast, productive — pick three

Borrows ideas from…

C++ — zero cost abstractions, RAII

Haskell — ADTs, type classes, pattern matching, local type inference

ML — general syntax

Cyclone — safe manual memory management

Overview

| 25.10.2018 | Rust and Eclipse5

Production Users: https://www.rust-lang.org/en-US/friends.html

Some Common Uses Today

| 25.10.2018 | Rust and Eclipse6

Systems / Infrastructure

high performance,

low latency,

low memory overhead

requirements

WebAssembly libraries Embedded into C/C++

applications for safety

critical parts

Embedded into other

language runtimes for

performance critical

parts

$

Command line

applications

Future Application Domains

| 25.10.2018 | Rust and Eclipse7

IoT / Embedded Asynchronous

networking

services

Key crates (APIs) and language features in these domains are not yet stable,

though already usable today

RustConf 2018 Talk: Getting Somethig for Nothing:

https://www.youtube.com/watch?v=t99L3JHhLc0

Embedded Hardware Development with Rust:

https://www.youtube.com/watch?v=g25xsK3HKkE

Awesome Embedded Rust (Overview Doc):

https://github.com/rust-embedded/awesome-embedded-rust

IoT Embedded Entry Points

| 25.10.2018 | Rust and Eclipse8

rustup — Toolchain version / install managerhttps://rustup.rs/

cargo — Build tool and package managerPackage registry: https://crates.io/

Several small helper tools (most triggered via cargo)

rustdoc — Creates HTML API documentation based on Markdown doc comments; can run code examples as tests

rustfmt — Formats Rust code based on standardized formatting rules

rls — Language server for Rust (for IDE integrations); in preview

cargo-clippy — Rust linter; in preview

Tool Infrastructure

| 25.10.2018 | Rust and Eclipse9

~$

...~$

Created binary (application) `helloworld` project

~/helloworld$

Compiling helloworld v0.1.0 (file:///home/mbu/rust/helloworld)

Finished dev [unoptimized + debuginfo] target(s) in 1.71s

Running `target/debug/helloworld`

Hello, world!

First Steps (On Linux)

| 25.10.2018 | Rust and Eclipse10

curl https://sh.rustup.rs -sSf | sh

cargo new helloworld && cd helloworld

cargo run

Answer some questions

Closures

Panicking vs. Error Type

Crates, modules and visibility

Cargo and dependency management

Macros

Explicit lifetime annotations

⇨ For more details, please visit introduction materials listed at the end

Many Important Topics Not Covered (Due to Time Constraints)

| 25.10.2018 | Rust and Eclipse11

Buckle up: First Example

| 25.10.2018 | Rust and Eclipse12

source: https://cheezburger.com/9191857664

use std::env;

fn main() {

let first_arg : Option<String> = env::args().skip(1).next();

let world : &str = "World";

let greetee = match first_arg {

Some(ref name) => name,

None => world

};

println!("Hello {}!", greetee);

}

(Unnecessarily Complicated) Hello World Example

| 25.10.2018 | Rust and Eclipse13

https://play.rust-lang.org/?gist=70a7f42d53d8639013a80a1cc02db61b&version=stable&mode=debug&edition=2015

Module import

Typed variable declaration Iterator combinator

Pattern matching expression

Reference type

Inferred

type

Macro invocation

Example Function

| 25.10.2018 | Rust and Eclipse14

https://play.rust-lang.org/?gist=76da1cf5724dc605a5ef144cab0886bc&version=stable&mode=debug&edition=2015

fn get_name(default : String) -> String {

let first_arg = env::args().skip(1).next();

first_arg.map_or(default, |s : String| {

// upper case first letter

let (first_char, rest) = s.split_at(1);

first_char.to_uppercase() + rest

} )

}

Function signature, types cannot be inferred

Closure

Tuple

destructuring

No ; ⇒ returns value from expression

2 Data Types

Pointer Sized Integers (Unsigned and Signed)

usize, isize

Example: let count : usize = 0xff;

Characters

char — 4 byte sized Unicode character

Example: let umbrella = '☂';

Never Type

! — No value (there is no instance), e.g. function that never returns

Example: fn forever() -> ! { loop {} }

More Primitive Types

https://play.rust-lang.org/?gist=b58a5b06d04a44d4f901d2720827332e&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse17

Array

[T;N]

Fixed size array; consecutively in memory

Example: let bytes : [u8;3] = [0x20,0x34,0x32];

Slice

[T]

Dynamically sized window into arrays

Usually only used as reference type &[T]

Example:

let s : &[u8] = &bytes[1..];

Tuple

(T, U, ..)

Sequence of possibly differently typed elements

Example:

let two_nums : (u32,f32) = (42, 3.14);

Compound Primitive Types

| 25.10.2018 | Rust and Eclipse18

https://play.rust-lang.org/?gist=ae76b70fe36a85a937ff952896d3a7c9&version=stable&mode=debug&edition=2015

Are user defined Algebraic Data Types / Tagged Unions

Values of the type hold one variant and a (hidden) discriminator

Examples from standard library:

Example usage:

let os : Option<u32> = Option::Some(42);

Enums

pub enum Option<T> {None,Some(T)

}

pub enum Result<T, E> {Ok(T),Err(E),

}

| 25.10.2018 | Rust and Eclipse20

Custom data type for grouping named values

Example:

struct Caterpillar {

name : String,

hunger : u8

}

// initialization

let harry = Caterpillar {

name : String::from("Harry"),

hunger : 100

};

Structs

| 25.10.2018 | Rust and Eclipse21

https://play.rust-lang.org/?gist=1ad79162e684e94c189195fcdfcdd5b6&version=stable&mode=debug&edition=2015

3 Memory Management

Rust ensures safe manual memory management checked at compile time

No garbage collector; does not fundamentally need reference counting

The memory management is built around concepts of ownership and borrowing

Ownership can be transferred, original data is not accessible anymore afterwards

Basics

23 | 25.10.2018 | Rust and Eclipse

Example of Ownership and Immutable Borrowing

24

https://play.rust-lang.org/?gist=152e2b2060d8ddb5af99d9b8213e86a0&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse

let mut owned_c : Caterpillar =Caterpillar { name : String::from("Harry"), hunger: 100 };

let borrowed_c : &Caterpillar = &owned_c;let hunger = (*borrowed_c).hunger; // only read access// actually * not needed most of the time, due to auto-derefprintln!("{}", hunger);

Example of Ownership and Mutable Borrowing

25

https://play.rust-lang.org/?gist=152e2b2060d8ddb5af99d9b8213e86a0&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse

let mut owned_c : Caterpillar = Caterpillar { /* … */ };

let mutably_borrowed_c : &mut Caterpillar = &mut owned_c;mutably_borrowed_c.hunger = 90; // look: auto-deref

Example of Transferring Ownership

26

https://play.rust-lang.org/?gist=152e2b2060d8ddb5af99d9b8213e86a0&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse

let mut owned_c : Caterpillar = Caterpillar { /* … */ };

let moved_c : Caterpillar = owned_c; // took ownership, but immutable now

IMHO: Biggest distinction from other (systems) programming languages

Its rules promise compile time memory safety and freedom from data races

Also: The Rust feature most new rusteaceans struggle with

The Borrow Checker

| 25.10.2018 | Rust and Eclipse27

Problems commonly associated with manual memory management:

Use after free (dangling pointer)

Double free

Not freeing memory (leak)

Buffer over- and underflow

Many of these problems can lead to safety & security issues

To its credit: C++ >=11 and Guidelines Support Library tackle some of the problems

The Borrow Checker: Problem Statement

| 25.10.2018 | Rust and Eclipse28

Prevented by Borrow Checker

Prevented by array implementation

and lack of raw pointers (in safe Rust)

#include <iostream>

#include <vector>

int main() {

std::vector<int> v {0};

int& e = v[0];

for(int i=1; i<5; i++) {

v.push_back(i);

}

std::cout << e;

return 0;

}

C++ Hidden Use After Free Example

| 25.10.2018 | Rust and Eclipse29

http://cpp.sh/2cpwg https://godbolt.org/z/WxcbO2

v

e

0 1 2 3 4

Single owner of every piece of memory at one time

When owner goes out of scope, memory is freed

References to owned memory can be “borrowed” (aliasing)

References must not outlive referenced memory (lifetimes)

Single exclusive access to memory, when access mutable

Or multiple immutable access at the same time; no mutable access

Some Important Borrow Checker Rules

| 25.10.2018 | Rust and Eclipse30

fn main() {

let mut v : Vec<i32> = vec![0];

let el : &i32 = &v[0];

for i in 1..=4 {

v.push(i);

}

println!("{}", el);

}

Example Violating Borrow Checker Rules

| 25.10.2018 | Rust and Eclipse31

https://play.rust-lang.org/?gist=8d3a9401792f6693f70de377bafa0694&version=stable&mode=debug&edition=2015

Example Compiler Output

32 | 25.10.2018 | Rust and Eclipse

error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable--> src\main.rs:29:3|

26 | let el = &v[0];| - immutable borrow occurs here

...29 | v.push(i);

| ^ mutable borrow occurs here...33 | }

| - immutable borrow ends here

For more information about this error, try `rustc --explain E0502`.error: Could not compile `testbin`.

To learn more, run the command again with --verbose.

use std::io::BufRead;

let mut lines = std::io::stdin().lock().lines();

while let Some(Ok(line)) = lines.next() {

println!("{}", line);

}

Example 2 Violating Borrow Checker Rules

33

https://play.rust-lang.org/?gist=7660f6853728d2cf7f48b7dd4970e6d6&version=stable&mode=debug&edition=2015

| 25.10.2018 | Präsentationstitel

Example 2 Compiler Output

34 | 25.10.2018 | Rust and Eclipse

error[E0597]: borrowed value does not live long enough--> src\main.rs:39:18|

39 | let mut lines = std::io::stdin().lock().lines();| ^^^^^^^^^^^^^^^^ - temporary value dropped here while still borrowed| || temporary value does not live long enough

...43 | }

| - temporary value needs to live until here|= note: consider using a `let` binding to increase its lifetime

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.

RefCell<T> — Thread local dynamically checked exclusive mutable access

Mutex<T> — Thread safe dynamically checked exclusive mutable access

Rc<T> — Thread local shared ownership

Arc<T> — Thread safe shared ownership

Some Escape Hatches: Borrow Checker Rules at Runtime

| 25.10.2018 | Rust and Eclipse35

The standard library provides some basic types for keeping memory on the heap

Box<T> — Single element

must always hold a value, there is no null-pointer

Example: let foo : Box<f32> = Box::new(3.14);

String — Owned strings are always kept on the heap

Collections: Multiple elements on the heap; re-sizable

Vec<T>, VecDeque<T>, LinkedList<T>, BinaryHeap<T>, HashSet<T>, BTreeSet<T>,

HashMap<K,V>, BTreeMap<K,V>

Heap Memory

| 25.10.2018 | Rust and Eclipse36

https://play.rust-lang.org/?gist=c383e368b831c85cef0bf4af2935b15a&version=stable&mode=debug&edition=2015

Internal Memory Layout Overview

| 25.10.2018 | Präsentationstitel37

https://docs.google.com/presentation/d/1q-c7UAyrUlM-eZyTo1pd8SZ0qwA_wYxmPZVOQkoDmH4

4 Control Flow

If expressions

Match expressions

Loop expressions

For loops

While loops

Infinite loops

? Operator

Control Flow Overview

| 25.10.2018 | Rust and Eclipse39

Since Expression, can evaluate to a value

If let can be used for simple destructuring

Example:

let random : u64 =

my_very_unsafe_random_gen();

let output = if random % 2 == 0 {

"Heads"

} else {

"Tails"

};

println!("{}", output);

If Expressions

https://play.rust-lang.org/?gist=6dee066ba8ffb2ef067070b0600d4ef3&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse40

let java_home : Result<String, _> =std::env::var("JAVA_HOME");

if let Ok(home_str) = java_home {println!("Your JAVA_HOME is : {}",

home_str);}

Match is similar to a switch in other languages, but over patterns

Can be used to de-structure structs, enums, tuples, arrays / slices

Match has to be exhaustive

Example:

let c : Caterpillar = construct_caterpillar();

let output = match c {

Caterpillar { ref name, .. } if name == "Harry" => String::from("Hi Harry!"),

Caterpillar { ref name, hunger: h @ 50...100 } => format!("Hi, {} you are {}% hungry!", name, h),

Caterpillar { name: ref n, hunger: 0...49 } => format!("Hi, {}", n),

Caterpillar { name: _, hunger: _ } => String::from("Impossibly hungry!"),

};

Match Expressions

https://play.rust-lang.org/?gist=42735afcf3785a0b6d84abe4963fc183&version=stable&mode=debug&edition=2015

| 25.10.2018 | Rust and Eclipse41

No traditional C-Style for-loops

For-in loops over types implementing IntoIterator trait

Examples:

for i in 1..=10 {

println!("{}", i)

}

for e in [1,2,3,5,8].iter() {

println!("{}", e)

}

For Loops

| 25.10.2018 | Rust and Eclipse42

https://play.rust-lang.org/?gist=f03ca224d5b2072615539a3ebdd1816f&version=stable&mode=debug&edition=2015

for (count,param) in std::env::args().enumerate() {

println!("Parameter {} is {}", count, param)

}

Loop continues until its condition evaluates to true

There is a while let variant(see 2nd Borrow Checker example), similar to if let

Example:

While Loops

| 25.10.2018 | Rust and Eclipse43

https://play.rust-lang.org/?gist=9814fa07fe79a0aa6b55044f1b173bab&version=stable&mode=debug&edition=2015

let mut curr = 1;while curr < 100 {

println!("{}", curr);curr *= 2;

}

May break with a value

Example:

Infinite Loops

| 25.10.2018 | Rust and Eclipse44

https://play.rust-lang.org/?gist=b2ea44f715a016af38ced22362fb8063&version=stable&mode=debug&edition=2015

use std::io::BufRead;

let stdin = std::io::stdin();

let user_input = loop {

let line = stdin.lock().lines().next();

if let Some(Ok(in_str)) = line {

break in_str;

}

};

The ? operator works differently than known from other languages

It is not the usual null-safe navigation

Extracts value from Option or Result; returns from function if used on None / Err

Example:

? Operator

| 25.10.2018 | Rust and Eclipse45

https://play.rust-lang.org/?gist=1bdd1afce12339140f6cf4a04c1b6680&version=stable&mode=debug&edition=2015

is transformed to

use std::str::from_utf8;let bytes : &[u8] = &[0x0020, 0x0034, 0x0032];let parsed : Result<&str, Utf8Error> = from_utf8(bytes);let s = parsed?.trim(); let s = match parsed {

Ok(inner) => inner.trim(),

Err(e) => return Err(e.into()),

};

5 Behavior for Data Types

Rust is no “classical” object oriented language

There is no inheritance between data types

Traits provide a way to define interfaces (with re-usable functionality)

General Categorization

| 25.10.2018 | Rust and Eclipse47

Impl blocks for a data type can be defined in same module as the data type

They hold functions that can be called on the type or values of the type

Behavior for Data Types

| 25.10.2018 | Rust and Eclipse48

struct Caterpillar {

name : String,

hunger : u8

}

struct Butterfly {

name : String

}

Data Type Behavior Example : Data Structures

| 25.10.2018 | Rust and Eclipse49

https://play.rust-lang.org/?gist=fdae8cf00e4d52ff319c736c1bbd5b9e&version=stable&mode=debug&edition=2015

impl Caterpillar {

fn new(the_name : &str) -> Caterpillar {

Caterpillar {

name : String::from(the_name),

hunger : 100

}

}

fn eat(&mut self, amount : u8) {

self.hunger =self.hunger.saturating_sub(amount);

}

fn transform(self) -> Butterfly {

Butterfly {

name : self.name

}

}

} // end impl Caterpillar

Data Type Behavior Example : Behavior

| 25.10.2018 | Rust and Eclipse50

https://play.rust-lang.org/?gist=fdae8cf00e4d52ff319c736c1bbd5b9e&version=stable&mode=debug&edition=2015

fn life_of_caterpillar_harry() {

let mut caterpillar = Caterpillar::new("Harry");

eat_some(&caterpillar);

let butterfly = caterpillar.transform();

caterpillar.eat(10);

}

fn eat_some(c : &Caterpillar) {

c.eat(50);

}

Data Type Behavior Example : Usage

| 25.10.2018 | Rust and Eclipse51

https://play.rust-lang.org/?gist=fdae8cf00e4d52ff319c736c1bbd5b9e&version=stable&mode=debug&edition=2015

Ownership already transferred

No mutable access

Are similar to interfaces of other languages; more similar to type classes in Haskell

Abstract a public API that can be implemented for types

Defines functions that must be implemented, or provide default implementations

May require other traits to also be implemented (similar to inheritance)

Can be implemented for types, if trait or type is located in same crate as implementation

Generics can define trait bounds, meaning a concrete type must have a trait implementation

Traits can be used as dyn reference (&dyn Trait); methods will be called via v-table

(dynamic dispatch)

Traits

| 25.10.2018 | Rust and Eclipse52

trait Emotions {

fn is_angry(&self) -> bool;

}

impl Emotions for Caterpillar {

fn is_angry(&self) -> bool {

self.hunger > 50

}

}

Trait Example

| 25.10.2018 | Rust and Eclipse53

https://play.rust-lang.org/?gist=9100b60676a020a24d788fc6a7c64904&version=stable&mode=debug&edition=2015

fn hangry_caterpillar() {

let c = Caterpillar::new("Harry");

if c.is_angry() {

println!("Leave him alone!");

}

}

// Silly example; see std::ops::Mul

trait Moar : Sized {

fn times(&self, usize) -> Self;

fn double(&self) -> Self {

self.times(2)

}

}

impl Moar for u32 {

fn times(&self, nr : usize) -> u32 {

self * (nr as u32)

}

}

Trait Example 2 : Default Implementations and Generic Use Over Trait

| 25.10.2018 | Rust and Eclipse54

https://play.rust-lang.org/?gist=cccab33989d4aa338e84a277c1af8add&version=stable&mode=debug&edition=2015

use std::fmt::Display;

fn print_double<T>(t : &T)

where T : Moar + Display {

println!("{}", t.double());

}

fn answer_to_question_of_life() {

print_double(&21);

}

trait Valueable : Display {

fn value(&self) -> usize;

}

impl Valueable for String {

fn value(&self) -> usize {

self.len()

}

}

fn print_value(item : &dyn Valueable) {

// item.value() dispatched via v-table

println!("{} has value {}", item, item.value())

}

Trait Example 3 : Dynamic Dispatch

| 25.10.2018 | Rust and Eclipse55

https://play.rust-lang.org/?gist=c34744420f4db7e72571f5264ae5887e&version=stable&mode=debug&edition=2015

6 IDE Story and Corrosion

LSP implementation that can be installed via rustup

Can be used as IDE / Editor backend providing “smarts”

Still in preview status

Seems to be unstable sometimes

Code completion sometimes incomplete (racer trades speed for accuracy)

Rust compiler needs some refactoring to be better designed for “pulling” info

The Rust Language Server — RLS

https://ncameron.org/blog/rls-1-0-release-candidate/

| 25.10.2018 | Rust and Eclipse57

Official Eclipse Foundation project for Rust support in the Eclipse IDE

Stands on the shoulders of giants

Eclipse CDT for debugging with GDB

Eclipse TM4E for syntax coloring and more

Eclipse LSP4E / LSP4J for editor support using RLS

https://www.eclipse.org/downloads/packages/release/2018-09/r/eclipse-ide-rust-developers-includes-incubating-components

Eclipse Corrosion

| 25.10.2018 | Rust and Eclipse58

LSP4J

RLS

TM4E

Corrosion

LSP4E CDT

Eclipse Corrosion : Current Features

| 25.10.2018 | Rust and Eclipse59

Compile Error Markers

Code Completion

Syntax Coloring

Outline

View

Find

References

• New project wizard (invoking cargo)

• Quick outline (Ctrl + O)

• Some quickfixes

(e.g. use suggestions for types not imported)

• Rename refactoring

Eclipse Corrosion: Some More Current Features

| 25.10.2018 | Rust and Eclipse60

• Compile/run via run configuration

• Debug rust programs (GDB only)

• Code formatting via RLS / rustfmt

• Navigate to definition

• Find implementations of traits / types

• Open symbol in workspace (Ctrl + Shift + T)

• Hover info

• Toggle comment

• Code folding (upcoming)

• Bracket matching and completion

• Code actions, e.g. continue started doc-comments (upcoming)

Eclipse Corrosion: Even More Current Features

| 25.10.2018 | Rust and Eclipse61

• Flat outline (RLS limitation)

• No unit test UI (mostly Rust limitation)

• Cannot show all trait implementations for type (LSP / RLS limitation)

• Very little refactoring capabilities (RLS limitation)

• No way to show all crate dependencies (LSP / RLS limitation)

Eclipse Corrosion: Some Current Limitations

| 25.10.2018 | Rust and Eclipse62

• No preview macro expansion in the editor (RLS limitation?)

• Hover info does not show specialized generic declarations (RLS limitation)

• Limited cargo support (e.g. cannot start benchmarks, doc generation etc.)

(Corrosion limitation)

• However, using an “External Tool” run configuration, specifying the command is possible

Eclipse Corrosion: More Current Limitations

| 25.10.2018 | Rust and Eclipse63

If you are used to Eclipse, Corrosion makes you feel right at home

Stability of the RLS & Corrosion combo got much better over the year

The overall package is still not what to expect from a full fledged IDE

Every now and then the language server stops working

Restart of Eclipse needed

Due to the stack it is not always clear which part is responsible for a problem

Where should a bug be reported?

Eclipse Corrosion, Experience Report

| 25.10.2018 | Rust and Eclipse64

7 Conclusion

Rust is a friendly systems programming language

Comes with build tool / package manager

→ Easy integration of external libraries / central lib repository

Fewer sharp edges (and errors at runtime) compared to C/C++

Guides to performant code

Eclipse Corrosion provides basic language support thanks to RLS

Rust and Eclipse have great and helpful communities

Conclusion

| 25.10.2018 | Rust and Eclipse66

Please Vote

| 25.10.2018 | Rust and Eclipse67

Into Rust (short intro videos)

http://intorust.com/

Learning Rust (quick introduction)

https://learning-rust.github.io/

The Rust Programming Language Book

https://doc.rust-lang.org/book/

Rust by Example

https://doc.rust-lang.org/rust-by-example/

The new Rustacean Podcast

https://newrustacean.com/

Rust-Learning (list of further resources)

https://github.com/ctjhoa/rust-learning

Entry Points for Learning Rust

| 25.10.2018 | Rust and Eclipse68

Fraunhofer FOKUS

Institute for Open Communication Systems

Kaiserin-Augusta-Allee 31

10589 Berlin, Germany

info@fokus.fraunhofer.de

www.fokus.fraunhofer.de

Max Bureck

Thank You for Your Attention