munificent / craftinginterpreters

Repository for the book "Crafting Interpreters"
http://www.craftinginterpreters.com/
Other
8.5k stars 1.01k forks source link

calling init() directly re-runes the constructor #1050

Open ludescher opened 2 years ago

ludescher commented 2 years ago

In Chapter 12.7.1 we try to prevent "re-initialization" of the constructor.

By calling this piece of code

class Foo {
    init(value) {
        print "init value: " + value;
    }
}

var foo = Foo("bar");
print foo.init("bug");

we expect this output

init value: bar
Foo instance
Foo instance

but what we actually get is

init value: bar
init value: bug
Foo instance

I'm no expert, but i would consider this behaviour unintended and thus being a bug.

I would suggest we disallow calling the constructor directly and make it a syntax error instead.

This is quite easy to implement, we update the method visitGetExpr in Resolver.java by checking for a get-expression with the name init and than we check if the call comes from inside a class or not.

@Override
public Void visitGetExpr(Expr.Get expr) {
    if (expr.name.lexeme.equals("init") && currentClass == ClassType.NONE) {
        Lox.error(expr.name, "Can't call init directly.");
    }

    resolve(expr.object);
    return null;
}

So the resolver will throw a syntax error and we don't get any headaches.