Dealing with unknown mutability in rust

89 Views Asked by At

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

1

There are 1 best solutions below

0
Chayim Friedman On BEST ANSWER

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.