Search code examples
rusttraitsmutability

Dealing with unknown mutability in rust


I'm having trouble understanding when to use mutable references as opposed to immutable references in traits.

The following example for a Visitor implementation is taken from Rust Design Patterns:

mod visit {
    use ast::*;

    pub trait Visitor<T> {
        fn visit_name(&mut self, n: &Name) -> T;
        fn visit_stmt(&mut self, s: &Stmt) -> T;
        fn visit_expr(&mut self, e: &Expr) -> T;
    }
}

This pattern works well when modifying a node as one traverses the AST is not needed. But for some use-case, altering a node as you traverse might be a design choice worth making.

The solution from the book comes in form of the folder pattern:

mod fold {
    use ast::*;

    pub trait Folder {
        fn fold_name(&mut self, n: Box<Name>) -> Box<Name> { ... }
        fn fold_stmt(&mut self, s: Box<Stmt>) -> Box<Stmt> { ... }
        fn fold_expr(&mut self, e: Box<Expr>) -> Box<Expr> { ... }
    }
}

A similar thing can be achieved by simply making each AST node mutable.

However, having both solutions seems to be tedious and not maintainable. For a large AST with many different nodes, there is a lot of code duplication; one Visitor instance must be created for mutable nodes and one for non-mutable nodes. Is there a better way of achieving this 'optional mutability'?


Solution

  • Replicating the visitor is the correct thing to do. Rust has no way to abstract over the mutability of a reference, and there are many examples of doing that, even in std (e.g. slice iterators). If this is too much boilerplate, you can use a macro to help with it.