Uma introdução ao sistema de tipos de Rust

Python Brasil - 2016 - #pybr12

Olá!

  • Engenheira da Computação
  • Programação
  • Eletrônica
  • Matemática
  • Física
  • Lego
  • Meetups
  • Bichinhos
  • Café
  • Pokémon
  • GIFs

#pybr12 @hannelita

Atenção

Isso não é um tutorial de introdução ao Rust

Teoria

Alguns tópicos podem gerar discussões. Opiniões pessoais nos slides

GIFs :)

Atenção

Ao final dos slides há um material de referência para introdução à linguagem

Agenda

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

#pybr12 @hannelita

Como você escolhe uma linguagem de programação?

#pybr12 @hannelita

  • Por causa da empresa
  • Por ser popular
  • Por causa do seu time
  • Por causa da data para entregar o projeto
  • Objetivo do projeto
  • Ferramentas disponíveis
  • Única linguagem que aprendi na faculdade
  • Alguém me recomendou esta linguagem
  • Sei lá :P

#pybr12 @hannelita

Com que frequência você considera os itens a seguir para escolher uma linguagem?

  • Sistema de Tipos
  • Imutabilidade
  • Evitar erros em tempo de execução
  • Paradigma
  • Verbosidade
  • Gerenciamento de memória

#pybr12 @hannelita

Péra - O que é um sistema de tipos?

De acordo com a Wikipedia:

"In programming languages, a type system is a collection of rules that assign a property called type to various constructs a computer program consists of"

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Péra - O que é um sistema de tipos?

#pybr12 @hannelita

Em todas as linguagens de programação, até mesmo em Assembly, possuímos dois componentes:

Dados

Operações

Nem todas as operações disponíveis fazem sentido para todos os tipos de dados

#pybr12 @hannelita

Se você usar partes incompatíveis de dados em uma operação, você terá um erro de representação.

#pybr12 @hannelita

Linguagens de programação usam um sistema de tipos para analisar um programa e determinar se um erro de representação ocorrerá ou não.

#pybr12 @hannelita

Quais são as estratégias possíveis que um sistema de tipos pode usar para tratar esses erros de representação?

#pybr12 @hannelita

Strategies

  • Gerar um erro de compilação
  • Checar os tipos antes de executar o código
  • Definir um conjunto fechado de erros que podem ser lançados
  • Erros de execução imprevisíveis
  • Conversão implícita para ajustar os tipos
  • O compilador rotula trechos de código e tenta inferir se o comportamento será válido ou não (antes da execução do programa)
  • O compilador ou interpretador gera código para rastrear os dados

#pybr12 @hannelita

Strategies

  • Gerar um erro de compilação
  • Checar os tipos antes de executar o código
  • Definir um conjunto fechado de erros que podem ser lançados
  • Erros de execução imprevisíveis
  • Conversão implícita para ajustar os tipos
  • O compilador rotula trechos de código e tenta inferir se o comportamento será válido ou não (antes da execução do programa)
  • O compilador ou interpretador gera código para rastrear os dados

"Strong"

"Weak"

"Static"

"Dynamic"

*As definições não são exatas na literatura

Strategies

  • Generate a compile error
  • Perform a type check before run the code
  • Well defined error set
  • Erros de execução imprevisíveis
  • Conversão implícita para ajustar os tipos
  • O compilador rotula trechos de código e tenta inferir se o comportamento será válido ou não (antes da execução do programa)
  • O compilador ou interpretador gera código para rastrear os dados

"Strong"

"Weak"

"Static"

"Dynamic"

  • Não tratar/ não fazer nada 

"Untyped"

Você não precisa escolher uma única alternativa.

Python: strong (os tipos não são alterados pelo interpretador) e dynamic (O interpretador rastreia os dados)

#pybr12 @hannelita

Uma estratégia para reduzir os erros é adotar um sistema de tipos static e strong

#pybr12 @hannelita

Java se encaixa em partes nessa descrição

Java pode causar problemas por conta do GC (coletor de lixo)

#pybr12 @hannelita

Usar C ou C++

Não há consenso se é weak ou strong

#pybr12 @hannelita

Rust vem para o resgate!

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Rust - funcionalidades

  • Memory safe, data race free
  • O compilador previne diversos erros em tempo de execução
  • Interface com C/C++
  • Generics
  • Polimorfismo 
  • Mantido pela Mozilla e por uma grande comunidade 

#pybr12 @hannelita

Rust - funcionalidades

  • Sem GC
  • Sem alocação manual de memória (malloc/free)
  • Sem seg faults

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Visão geral de Rust

fn main() {
    fizzbuzz_to(100);
}

fn is_divisible_by(lhs: u32, rhs: u32) -> bool {
    if rhs == 0 {
        return false;
    }
    lhs % rhs == 0
}

fn fizzbuzz(n: u32) -> () {
    if is_divisible_by(n, 15) {
        println!("fizzbuzz");
    } else if is_divisible_by(n, 3) {
        println!("fizz");
    } else if is_divisible_by(n, 5) {
        println!("buzz");
    } else {
        println!("{}", n);
    }
}

fn fizzbuzz_to(n: u32) {
    for n in 1..n + 1 {
        fizzbuzz(n);
    }
}
source: http://rustbyexample.com/fn.html

Inferência de tipos limitada. Declaração de tipos explícita para parâmetros e tipo de retorno de uma função.

Macros

Visão geral de Rust

fn main() {
    let _immutable_binding = 1;
    let mut mutable_binding = 1;
    println!("Before mutation: {}", mutable_binding);
    // Ok
    mutable_binding += 1;
    println!("After mutation: {}", mutable_binding);

    // Error!
    _immutable_binding += 1;
    // FIXME ^ Comment out this line
}
source: http://rustbyexample.com/variable_bindings/mut.html

Imutabilidade por padrão

Visão Geral de Rust

fn is_odd(n: u32) -> bool {
    n % 2 == 1
}

fn main() {
    println!("Find the sum of all the squared odd numbers under 1000");
    let upper = 1000;
    let mut acc = 0;
    for n in 0.. {
        let n_squared = n * n;
        if n_squared >= upper {
            break;
        } else if is_odd(n_squared) {
            acc += n_squared;
        }
    }
    println!("imperative style: {}", acc);
    let sum_of_squared_odd_numbers: u32 =
        (0..).map(|n| n * n)             // All natural numbers squared
             .take_while(|&n| n < upper) // Below upper limit
             .filter(|n| is_odd(*n))     // That are odd
             .fold(0, |sum, i| sum + i); // Sum them
    println!("functional style: {}", sum_of_squared_odd_numbers);
}
source: http://rustbyexample.com/fn/hof.html

High 

Order

Functions

Outras funcionalidades - Tuples, Enums, Structures, Traits.

#pybr12 @hannelita

Como se livrar de seg faults?

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Variable bindings possuem (own) os valores em Rust

fn foo() {
    let v = vec![1, 2, 3];
    let v2 = v;

    println!("v[0] is: {}", v[0]);
}

#pybr12 @hannelita

Variable bindings possuem (own) os valores em Rust

fn foo() {
    let v = vec![1, 2, 3];
    let v2 = v;

    println!("v[0] is: {}", v[0]);
}
O compilador de Rust reclama:
"error: use of moved value: `v`
println!("v[0] is: {}", v[0]);"

O quê?

#pybr12 @hannelita

Isso pode soar pouco prático, mas ajuda a previnir diversos erros em tempo de execução.

#pybr12 @hannelita

Rust permite que alguns valores sejam partilhados através de uma funcionalidade chamada 'borrowing'

#pybr12 @hannelita

fn main() {
    fn sum_vec(v: &Vec<i32>) -> i32 {
        return v.iter().fold(0, |a, &b| a + b);
    }
    fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
        let s1 = sum_vec(v1);
        let s2 = sum_vec(v2);
        s1 + s2
    }

    let v1 = vec![1, 2, 3];
    let v2 = vec![4, 5, 6];

    let answer = foo(&v1, &v2);
    println!("{}", answer);
}

Borrowing

&

#pybr12 @hannelita

Muito similar a estratégia de "Read-Writers Lock"

  • Muitos readers de uma vez OU um único writer com acesso exclusivo
  • Read only não requer acesso exclusivo
  • Acesso exclusivo não permite outros readers
(More info: https://users.cs.duke.edu/~chase/cps210-archive/slides/moresync6.pdf )

Rust usa um modelo similar em tempo de compilação.

Muito similar a estratégia de "Read-Writers Lock"

  • Muitos readers de uma vez OU um único writer com acesso exclusivo
  • Read only não requer acesso exclusivo
  • Acesso exclusivo não permite outros readers

Rust usa um modelo similar em tempo de compilação.

T: Base type; possui um valor

&T: Reader compartilhado

&mut T: Writer exclusivo

(Note: Não estou considerando a feature de Copy nesses slides!)

Muito similar a estratégia de "Read-Writers Lock"

  • Muitos readers de uma vez OU um único writer com acesso exclusivo
  • Read only não requer acesso exclusivo
  • Acesso exclusivo não permite outros readers

Rust usa um modelo similar em tempo de compilação.

T: Base type; possui um valor

&T: Reader compartilhado

&mut T: Writer exclusivo

(Note: Não estou considerando a feature de Copy nesses slides!)

Referência imutável

Referência mutável

Alguns problemas que o borrowing previne:

  • Iteradores inválidos
  • Problemas com Data race
  • Utilizar um valor após o free

#pybr12 @hannelita

Falando nisso, como performar um free em uma variável em Rust? Não há GC; como limpo a memória?

#pybr12 @hannelita

Péra, eu também não poderia bagunçar a técnica de borrowing se eu liberasse uma variável que está emprestada?

#pybr12 @hannelita

#pybr12 @hannelita

Não precisamos lidar com isso manualmente. Pelo menos não de forma explícita :)

#pybr12 @hannelita

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Em Rust, cada referência possui um lifetime (tempo de vida) associado.

fn lifetimes() {

    let a1 = vec![1, 2, 3]; //                 +
    let a2 = vec![4, 5, 6]; //            +    |
                            //            |    |
    let b1 = &a1;           //       +    |    |
    let b2 = &a2;           //  +    |    |    |
    foo(b1);                //  |    |    |    |
    foo(b2);                // 'b2  'b1  'a2  'a1
                            //  |    |    |    |
}  

#pybr12 @hannelita

Você pode explicitar os lifetimes em Rust

fn explicit_lifetime<'a>(x: &'a i32) {
}

Ou até mesmo múltiplos lifetimes

fn multiple_lifetimes<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
}

#pybr12 @hannelita

Ao final de um lifetime, ocorrerá um free.

#pybr12 @hannelita

  • GC não é necessário
  • Mecanismo para evitar dangling pointers
  • malloc e free não são necessários manualmente

Alguns problemas que o sistema de lifetime ajuda a prevenir:

#pybr12 @hannelita

Ok, então Rust é sempre seguro em termos de memória?

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Rust é seguro não somente devido ao borrowing e ao lifetime

#pybr12 @hannelita

Rust possui um bom sistema de tipos genéricos, Traits e Closures

http://huonw.github.io/blog/2015/05/finding-closure-in-rust/

#pybr12 @hannelita

É possível invocar código C/C++ a partir do Rust. Mas C/C++ não garante a mesma segurança de alocação de memória.

#pybr12 @hannelita

unsafe

fn main() {
    let u: &[u8] = &[49, 50, 51];

    unsafe {
        assert!(u == std::mem::transmute::<&str, &[u8]>("123"));
    }
}

#pybr12 @hannelita

Chamadas explícitas com unsafe.

#pybr12 @hannelita

Rust é perfeito?

#pybr12 @hannelita

Agenda

#pybr12 @hannelita

  • Escolhendo uma linguagem de programação
  • Introdução aos tipos
  • Por que Rust é interessante
  • Visão geral da estrutura de Rust
  • Borrow
  • Lifetime
  • Sobre segurança de tipos em Rust
  • Os pontos fracos de Rust

Reclamações sobre Rust

  • Curva de aprendizado é um pocuo lenta
  • Muitos conceitos novos
  • Linguagem relativamente nova no mercado

#pybr12 @hannelita

Reclamações sobre Rust

  • Curva de aprendizado é um pocuo lenta
  • Muitos conceitos novos
  • Linguagem relativamente nova no mercado

Respostas de Rust para resolver os problemas

  • Documentação rica e recusros de aprendizagem
  • A comunidade é ativa e amigável
  • A comunidade tem construído diversas ferramentas e bibliotecas para enriquecer os recursos disponíveis.

#pybr12 @hannelita

Bônus #1: Pergunta final - qual é o sistema de tipos de Rust?

#pybr12 @hannelita

Resposta: Aproximamos para e strong. Há um projeto de pesquisa para descrever o sistema de tipos de Rust:

https://www.ralfj.de/blog/2015/10/12/formalizing-rust.html

#pybr12 @hannelita

Bônus #2

O tópico sobre sistema de tipos é interessante! Quais são os próximos passos para se aprofundar?

Resposta: Lambda Calculus e Type Theory :)

#pybr12 @hannelita

http://slides.com/hannelitavante-hannelita/type-theory-101-35#/

Bônus #3

Free GIF! 

Referências

  • https://www.youtube.com/watch?v=Q7lQCgnNWU0
  • https://www.quora.com/Why-do-programming-languages-use-type-systems
  • http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html
  • http://lucacardelli.name/papers/typesystems.pdf
  • https://www.ralfj.de/blog/2015/10/12/formalizing-rust.html
  • http://jadpole.github.io/rust/type-system
  • https://wiki.haskell.org/Typing
  • https://gist.github.com/Kimundi/8391398
  • https://www.smashingmagazine.com/2013/04/introduction-to-programming-type-systems/

(Alguns desses links não são muito científicos)

Referências - Introdução ao Rust

  • https://doc.rust-lang.org/book/
  • https://doc.rust-lang.org/reference.html
  • https://doc.rust-lang.org/nomicon/
  • Rust e Pokémons -                                              http://slides.com/hannelitavante-hannelita/rust-and-pokmons#/

Agradecimentos especiais

  • Comunidade de Rust e Rust SP - https://www.meetup.com/Rust-Sao-Paulo-Meetup/ e @bltavares
  • B.C., pela revisão constante
  • @ramalhoorg
  • Time da Python Brasil

Obrigada :)

Perguntas?

 

hannelita@gmail.com

@hannelita