3

I have an enum Expr:

enum Expr {
    Const(i32),
    Add {
        lhs: Expr,
        rhs: Expr,
    },
}

If I compile this, I get the error telling me that I have recursive types without indirection. There are at least two ways of adding indirection:

  1. Boxing each field in Expr::Add:

    Add {
        lhs: Box<Expr>,
        rhs: Box<Expr>,
    }
    
  2. Extracting Expr::Add to a separate struct and then Boxing it in the enum variant:

    struct ExprAdd {
        lhs: Expr,
        rhs: Expr,
    }
    
    enum Expr {
        Const(i32),
        Add(Box<ExprAdd>),
    }
    

The first way of doing things introduces excessive Boxing. That is, the number of Boxes is equal to the number of fields in the Expr::Add variant and instantiating Expr::Add is verbose:

let e = Expr::Add { 
    lhs: Box::new(Expr::Const(1)),
    rhs: Box::new(Expr::Const(2)),
};

However, it allows for convenient pattern matching:

let e = Expr::Const(1);
match e {
    Expr::Const(c) => {}
    // Convenient destructuring.
    Expr::Add { lhs, rhs } => {}
}

The second way of doing things is more efficient due to the usage of only one Box but it is unnecessarily verbose(ExprAdd struct is not really needed here) and pattern matching is limited:

let e = Expr::Const(1);
match e {
    Expr::Const(c) => {}
    // No convenient destructuring.
    // `expr` is of type `ExprAdd`.
    // Expr::Add(Box(ExprAdd { lhs, rhs })) => {} // fails because `Box` has private members.
    Expr::Add(expr) => { /* use `expr.lhs` and `expr.rhs` */ }
}

Questions

  1. Which is better? Which is more idiomatic?
  2. Is there a way of declaring a recursive enum like in the second example that allows convenient pattern matching like in the first example?
  • 1
    On nightly you could activate box patterns, but you're probably not on nightly. – Masklinn Mar 23 '20 at 12:48
  • It's hard to answer multiple questions made in one post. Please separate them into multiple questions so that we can help you better and so that your questions will help others in the future that have one of the same questions as you! – Shepmaster Mar 23 '20 at 13:57
  • It looks like your question might be answered by the answers of [Is it impossible to have a nested match on a recursive datatype that uses a smart pointer like a Box, Rc, or Arc?](https://stackoverflow.com/q/48246510/155423); [How to pattern match a Box to get a struct's attribute?](https://stackoverflow.com/q/52398060); [How to pattern match on values inside a type implementing Deref, such as Box, without copying the contents?](https://stackoverflow.com/q/53132035). If not, please **[edit]** your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Mar 23 '20 at 14:00

0 Answers0