Search code examples
c#genericsinterpreterexpressionvisitor

Trouble with generics when trying port the LOX language implementation from the Crafting Interpreter's book to C#


I have recently caught the language bug, and as part of my learning process I have begun working my way through the Crafting Interpreters book by Bob Nystrom and attempting to recreate the JLOX language interpreter in C#.

The "J" in JLOX refers to the sample code in the Book being implemented in Java.

In the "Working with Trees" and "A (Not Very) Pretty Printer" sections of the bok, Bob introduces the Visitor pattern as a solution to the "Expression Problem".

I have attempted to translate the Java code into C#, but am now stumped with the following compiler error:

"ASTPrinter.VisitBinaryExpr(Expression.Binary): No suitable method found to override" (click to see the image)

The two relevant code files are:

Expression.cs:

using System;

namespace CSharpLox
{
    abstract public class Expression
    {
        abstract public T Accept<T>(Visitor<T> visitor);

        public interface Visitor<T>
        {
            T VisitBinaryExpr(Binary expr);
            // other expression type visitors removed for clarity...
        }

        public class Binary : Expression
        {
            public readonly Expression left;
            public readonly Token _operator;
            public readonly Expression right;

            public Binary(Expression left, Token _operator, Expression right)
            {
                this.left = left;
                this._operator = _operator;
                this.right = right;
            }

            override public T Accept<T>(Visitor<T> visitor)
            {
                return visitor.VisitBinaryExpr(this);
            }
        }

        // other expression types removed for clarity...
    }
}

And ASTPrinter.cs:

using System;
using System.Text;

namespace CSharpLox
{
    // ASTPrinter.cs
    public class ASTPrinter : Expression.Visitor<string>
    {
        override public string VisitBinaryExpr(Expression.Binary expression)
        {
            return parenthesize(expression._operator.lexeme, expression.left, expression.right);
        }

        private String parenthesize(String name, params Expression[] expressions)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("(").Append(name);

            foreach (Expression expression in expressions)
            {
                builder.Append(" ");
                builder.Append(expression.Accept(this));
            }

            builder.Append(")");

            return builder.ToString();
        }
    }
}

The error that I don't know how to solve is on this line of ASTPrinter.cs:

override public string VisitBinaryExpr(Expression.Binary expression)

The error text reported by the Visual Studio editor is:

Error CS0115 'ASTPrinter.VisitBinaryExpr(Expression.Binary)': no suitable method found to override

I guess I just don't know enough about C# generic return types.

I have been trawling around looking for information about generic return types, but so far I have not found a clear example of how it would interact with the concrete implementation of an abstract interface. Or perhaps this is an area where the Generics capabilities of C# and Java differ too much for a direct translation of the implementation.

Any advice would be appreciated.


Solution

  • Your Expression.Visitor<string> is an interface so there is nothing to override.

    Simply put:

    public string VisitBinaryExpr(Expression.Binary expression)
    

    You only need to override when a base class has already defined a method with the same signature that was declared as vitrual or abstract.

    In your case the class ASTPrinter derives directly from System.Object.