This is part of interpreter for a simple language. The language also includes strings, lists, functions, etc and the corresponding functions evalString, evalList, etc. functions in the Evaluator. Only the Number subclass and evalNumber function are shown.
The Evaluator.evaluate function calls Expr.eval, and each Expr subclass calls the correct Evaluator function (evalNumber, evalString, evalList, etc.) to evaluate the expression.
import std.stdio;
import std.string;
abstract class Expr {
Out eval(Out)(Evaluator!Out evaluator);
}
class Number: Expr {
double num;
this(double _num) { num = _num; }
override Out eval(Out)(Evaluator!Out evaluator) {
return evaluator.evalNumber(this);
}
}
class Evaluator(Out) {
Out evaluate(Expr expr) {
return expr.eval(this); // ### Error is here ###
}
abstract Out evalNumber(Number number);
}
class ExprPrinter: Evaluator!string {
override string evalNumber(Number num) {
return format("%s", num.num);
}
}
void main() {
Number n = new Number(5);
auto printer = new ExprPrinter();
writefln("Number: %s", printer.evaluate(n));
}
When I try to build it, I get
example.o: In function `_D7example__T9EvaluatorTAyaZQp8evaluateMFCQBo4ExprZQBb':
/home/neniu/projects/duover/source/example.d:19: undefined reference to `_D7example4Expr__T4evalTAyaZQkMFCQBf__T9EvaluatorTQBaZQpZQBh'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
If I read the mangle correctly, the compiler is saying that the expr.eval on line 19 (marked in the code) is referring to a function which is not defined, but (in this case) the Number.eval function is supposed to be that function.
I have tried changing line 19 to include the Out specialisation
return expr.eval!Out(this);
but that made no difference at all.
What am I missing here? How can I get the expr.eval(this) call to resolve to Number.eval?
This is with DMD 2.081.1.
Thank you.
*&When I try to build it, I get
example.o: In function `_D7example__T9EvaluatorTAyaZQp8evaluateMFCQBo4ExprZQBb':
/home/neniu/projects/duover/source/example.d:19: undefined reference to `_D7example4Expr__T4evalTAyaZQkMFCQBf__T9EvaluatorTQBaZQpZQBh'
collect2: error: ld returned 1 exit status
Error: linker exited with status 1
If I read the mangle correctly, the compiler is saying that the expr.eval on line 19 (marked in the code) is referring to a function which is not defined, but (in this case) the Number.eval function is supposed to be that function.
I have tried changing line 19 to include the Out specialisation
return expr.eval!Out(this);
but that made no difference at all.
What am I missing here? How can I get the expr.expr(this) call to resolve to Number.eval?
This is with DMD 2.081.1.
Thank you.
* Edit *
I tried making Expr.eval abstract (with and without the abstract qualifier to the class itself, since that is the function that each subclass has to override:
abstract class Expr {
abstract Out eval(Out)(Evaluator!Out evaluator);
}
but now the compiler complains
example.d(5): Error: function `example.Expr.eval!string.eval` final functions cannot be abstract
example.d(28): Error: template instance `example.Expr.eval!string` error instantiating
example.d(35): instantiated from here: Evaluator!string
I don't want Expr.eval to be final. I've done nothing to make Expr.eval final. I don't see why this makes Expr.eval final. How do I make Expr.eval not final so I can make it abstract so I can -- no, have to -- override it?
Wouldn't declaring something as abstract ("You have to override this function") be exactly the opposite of declaring it final ("You can not override this function")?