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