Is there an easy way to mimic generics with an accept method of a visitor pattern?

Paul Backus snarwin at gmail.com
Thu Feb 18 13:53:19 UTC 2021


On Thursday, 18 February 2021 at 11:14:05 UTC, Mina wrote:
> I'm following along with the crafting interpreters book 
> (https://craftinginterpreters.com) and it goes into 
> implementing a visitor pattern that returns generic types, so 
> implementing it in D came down to the accept method causing 
> undefined symbol error that goes away when changing it to 
> returning a concrete type, so here's what I've got working 
> (https://github.com/MKamelll/dlox/blob/main/source/loxast.d) 
> and here's the book's implementation 
> (https://github.com/munificent/craftinginterpreters/blob/master/java/com/craftinginterpreters/lox/Expr.java).
>
>
> Thanks.

In D, because generics are implemented using templates 
("monomorphization"), generic methods can't be virtual and can't 
be overridden in child classes. As you've discovered, that means 
`accept` has to work entirely with concrete types rather than 
generic ones.

One way to solve this (which is used in the D compiler's source 
code) is to have both `accept` and `visit` return `void` and put 
the result inside the visitor object as a member variable. For 
example:

interface Visitor
{
     void visit(Expr.Literal expr);
     // etc.
}

class AstPrinter : Visitor
{
     string result;

     override void visit(Expr.Literal expr)
     {
         if (!expr.literal.hasValue) result =  "nil";
         else result = lexLiteralStr(expr.literal);
     }

     // etc.

     string print(Expr expr)
     {
         expr.accept(this);
         return result;
     }
}

Another possibility is to use discriminated unions and tag-based 
dispatch (i.e., switch statements) instead of classes and virtual 
method dispatch. This would make it a bit harder to follow the 
book, but might be a better learning experience if you're up for 
a challenge.


More information about the Digitalmars-d-learn mailing list