Rust: além de OO

Quem sou eu?

  • Preguiçoso.
  • Autor da Boost.Http (NÃO é uma biblioteca oficial Boost (ainda!)).
  • Entusiasta de software livre.
  • Programador Rust, C++, Qt, MongoDB...
  • Mais novo interesse: escola austríaca de economia.

Organização: OO

Ideias:

  • Tipo abstrado de dados.
  • Herança.
  • Polimorfismo.

OO: Exemplo #1

Abstração de dados.

public class Shape {}

public class Circle extends Shape {}

public class Triangle extends Shape {}

OO: Exemplo #2

public abstract class Shape {
    abstract double area();
}

public class Circle extends Shape {
    double area() {
        // pi * r²
    }
}

public class Triangle extends Shape {
    double area() {
        // b * h / 2.0
    }
}

OO: Exemplo #2

  • Hierarquia aberta para tipos e fechada para algoritmos.
  • Algoritmos de aridade 1.

OO: Exemplo #3

public abstract class Shape {
    abstract void accept(Visitor v);
}

public class Circle extends Shape {
    void accept(Visitor v) {
        v.visit(this);
    }
}

public class Triangle extends Shape {/* ... */}

public class Visitor {
    void visit(Circle c) {/*...*/}
    void visit(Triangle t) {/*...*/}
}

public class Collides extends Visitor {/*...*/}

Exemplo #3

  • Visitor.
  • Hierarquia aberta a novos algoritmos.
  • Boilerplate everywhere.

Exemplo #4: não-OO (hacky)

public class Circle extends Shape {
    // ...
}

public class Triangle extends Shape {
    // ...
}

public abstract class Algorithms {
    double area(Shape o) {
        if (o instanceof Circle) {
            // pi * r²
        } else if (o instanceof Triangle) {
            // b * h / 2.0
        }
    }
}

Exemplo #5 (aridade 2)

public abstract class Shape {
    abstract boolean collides(Shape o);
}

public class Circle extends Shape {
    boolean collides(Shape o) {
        if (o instanceof Circle) {
            // algorithm C
        } else if (o instanceof Triangle) {
            // algorithm C-T
        }
    }
}

public class Triangle extends Shape {
    boolean collides(Shape o) {
        if (o instanceof Circle) {
            // algorithm C-T
        } else if (o instanceof Triangle) {
            // algorithm T
        }
    }
}

Exemplo 5

  • Continua hacky.
  • Aridade 2.
  • Tipos são agrupados, mas algoritmos ficam espalhados.

Exemplo #6

public abstract class Shape {
    abstract void accept(Visitor v);
}

public class Circle extends Shape {/*...*/}
public class Triangle extends Shape {/*...*/}

public abstract class Visitor {
    void visit(Circle c) {/*...*/}
    void visit(Triangle t) {/*...*/}

    boolean evaluate(Shape a, Shape b) {/*...*/}

    abstract boolean evaluate(Triangle t1, Triangle t2);
    abstract boolean evaluate(Triangle t, Circle c);
    abstract boolean evaluate(Circle c, Triangle t);
    abstract boolean evaluate(Circle c1, Cricle c2);
}

public class CollidesVisitor extends Visitor {
    boolean evaluate(Triangle t1, Triangle t2) {/*...*/}
    boolean evaluate(Triangle t, Circle c) {/*...*/}
    boolean evaluate(Circle c, Triangle t) {/*...*/}
    boolean evaluate(Circle c1, Cricle c2) {/*...*/}
}

Exemplo #7

abstract class Expression {
    public abstract object Accept(Visitor v);
}

class ConstantExpression : Expression {
    public int constant;

    public override object Accept(Visitor v) {
        return v.VisitConstant(this);
    }
}

class SumExpression : Expression {
    public Expression left, right;

    public override object Accept(Visitor v) {
        return v.VisitSum(this);
    }
}

interface Visitor {
    object VisitConstant(ConstantExpression e);
    object VisitSum(SumExpression e);
}

class EvaluateVisitor : Visitor {
    public object VisitConstant(ConstantExpression e) {
        return e.constant;
    }

    public object VisitSum(SumExpression e) {
        return (int)e.left.Accept(this)
            + (int)e.right.Accept(this);
    }
}

Exemplo 8

  • Duas hierarquias: Animal e Transporte.
  • Pergunta: animal a pode usar transporte t?

    bool is_valid(Animal a, Transport t);

OO: Outras considerações

  • Multimethods (parcialmente abordado aqui).
  • Problema do diamante (mais famoso). Ainda visão aridade-1.

Abordagem Rust

enum MyBool {
    MyTrue,
    MyFalse
}

fn is_odd(x: i32) -> MyBool {
    if x % 2 != 0 {
        MyBool::MyTrue
    } else {
        MyBool::MyFalse
    }
}

Rust, enum prático

enum MyBool {
    MyTrue,
    MyFalse
}

fn is_odd(x: MyBool) -> bool {
    match x {
        MyBool::MyTrue => true,
        MyBool::MyFalse => false,
    }
}

Rust, poderoso enum

enum Option {
    Some(i32),
    None
}

fn lexical_cast(text: String) -> Option {
    // ...

    return Option::None;

    // ...

    return Option::Some(val);
}

Hierarquias com enum

enum Shape {
    Circle(f32),
    Triangle(f32, f32),
}

// Algoritmo não-macarrônico
fn area(x: Shape) -> f32 {
    match x {
        Shape::Circle(r) => PI * r * r,
        Shape::Triangle(b, h) => b * h / 2.0,
    }
}

Mais hierarquias

enum Shape {
    Circle(/*...*/),
    Triangle(/*...*/),
}

fn collides(a: Shape, b: Shape) -> bool {
    match (a, b) {
        (Shape::Circle(/*...*/), Shape::Circle(/*...*/)) => {
            // C-C
        }
        (Shape::Circle(/*...*/), Shape::Triangle(/*...*/)) => {
            // C-T
        }
        (Shape::Triangle(/*...*/), Shape::Circle(/*...*/)) => {
            // T-C
        }
        (Shape::Triangle(/*...*/), Shape::Triangle(/*...*/)) => {
            // T-T
        }
    }
}

Eliminando redundâncias

enum Shape {
    Circle(/*...*/),
    Triangle(/*...*/),
}

fn collides(a: Shape, b: Shape) -> bool {
    match (a, b) {
        (Shape::Circle(/*...*/), Shape::Circle(/*...*/)) => {
            // C-C
        }
        (Shape::Circle(/*...*/), Shape::Triangle(/*...*/)) => {
            // C-T
        }
        (Shape::Triangle(/*...*/), Shape::Triangle(/*...*/)) => {
            // T-T
        }
        _ => {
            collides(b, a)
        }
    }
}

Animal e transporte

enum Animal { Horse, Dog, Cat }
enum Transport { Car, Airplane }

fn is_valid(a: Animal, t: Transport) -> bool {
    match (a, t) {
        (Animal::Horse, Transport::Car) => false,
        (Animal::Dog, Transport::Car) => true,
        (Animal::Cat, Transport::Car) => true,
        (Animal::Horse, Transport::Airplane) => true,
        (Animal::Dog, Transport::Airplane) => true,
        (Animal::Cat, Transport::Airplane) => true,
    }
}

Flexibilidade

enum Animal {
    Cat, // ...
}

enum AnimalSomething {
    Insect, // ...
}

fn convert(a: Animal) -> AnimalSomething {
    Animal::Cat | Animal::Dog => AnimalSomething::Ugly,
    Animal::Whale => /*...*/,
    // ...
}

Flexibilidade++

struct Triangle {
    b: f32,
    h: f32
}

struct Circle {/*...*/}

enum Shape {
    Triangle(Triangle),
    Circle(Circle),
    // ...
}

enum ClosedShape {
    Triangle(Triangle),
    Circle(Circle),
}