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'?
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.