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.

Reply via email to