Destructuring

I lot of my programming is structuring and destructuring data. An interesting area for structuring data is enums. Rust allows three variant types: unit-like, tuple-like, and struct-like. rlox uses enums to represent valid lox expressions:

struct Token;
struct Object;

pub enum Expr<'a> {
    Binary(Box<Expr<'a>>, &'a Token, Box<Expr<'a>>),
    Grouping(Box<Expr<'a>>),
    Literal(Object),
    Unary(&'a Token, Box<Expr<'a>>),
}

Matching on this enum is easy too:

let e = Expr::Literal(Object);
match e {
    Expr::Binary(left, token, right) => {}
    Expr::Grouping(group) => {}
    Expr::Literal(object) => {}
    Expr::Unary(token, right) => {}
}

When I first wrote the code for rlox's Expr implementation, I created separate structs for each variant (that needed one).

struct Token;
struct Object;

enum Expr<'a> {
    Binary(Binary<'a>),
    Grouping(Grouping<'a>),
    Literal(Object),
    Unary(Unary<'a>),
}

struct Binary<'a> {
    left: Box<Expr<'a>>,
    token: &'a Token,
    right: Box<Expr<'a>>,
}

struct Grouping<'a> {
    grouping: Box<Expr<'a>>,
}

struct Unary<'a> {
    token: &'a Token,
    right: Box<Expr<'a>>,
}

This is a lot more code and adds another level of indirection while matching:

let e = Expr::Literal(Object);
match e {
    Expr::Binary(b) => {}
    Expr::Grouping(group) => {}
    Expr::Literal(object) => {}
    Expr::Unary(u) => {}
}