Godot: Subclasses do not inherit _init when extended

Created on 12 Jan 2018  路  9Comments  路  Source: godotengine/godot

Godot version:
2cde466ebdb6237b6f72ef78614dc05f2ffb551b

OS/device including version:
Windows 10 64bit

Issue description:
From what I can tell subclasses do not inherit the _init function when they are extended

extends Node

class test:
    func  _init(t = 0):
        print(t)

class test2 extends test:
    var nothing = 0

func _ready():
    test.new(100)
    test2.new(4)

this code prints 100 and then throws an error of Invalid call to function 'new' in 'GDScript'. Expected 0 arguments. at line 12 test2.new(4)

Steps to reproduce:
You can either run the reproduction project, or paste the code above and run it.

Minimal reproduction project:
subclass_bug.zip

  • [x] I searched the issues for other issues like this.
bug gdscript

Most helpful comment

You didn't declared the _init(arg) for your class test2.
You may try this

class test2 extends test:
    var nothing = 0
    func  _init(t = 0).(t):
        pass

All 9 comments

You didn't declared the _init(arg) for your class test2.
You may try this

class test2 extends test:
    var nothing = 0
    func  _init(t = 0).(t):
        pass

Maybe needs to be better documented?

Writing an additional signature doesn't make any sense if I'm not actually going to do something inside that new definition. It's just more code I have to write to do exactly what I want it to do.

Yeah actually I agree this shouldn't be needed.

@akien-mga Is this something you don't see being possible before 3.0?
@Geequlim I appreciate the knowledge of the possible workaround at the moment.

Yes it's too late for 3.0.

I have another example of this for reference:

extends KinematicBody2D

var state = B.new(self)

class A:
    var player = "test"
    func _init(p_player = "test2"):
        player = p_player
        call("randomfunc")

class B extends A:
    func _init(p_player = "test3"):
        ._init(p_player)
    func randomfunc():
        print("Hello: ", player)

Prints:

Hello: test2
Hello: [KinematicBody2D:1120]

First the base class's _init() callback fires, but it completely ignores any inputted parameter and runs with whatever the default value is. I think this is another part of the bug that should still use the provided value.

Then the derived class's callback fires, but because we instanced the derived version (my guess), it actually does plug in the parameter we passed. I then manually called the base class's constructor callback a second time via the "parent call" syntax (notated by the preceding '.' in the method call).

My initial issue might be related to this
https://github.com/godotengine/godot/blob/master/modules/gdscript/gdscript_compiler.cpp#L1611
0 is hardcoded for the number of arguments for the default _init function, I'm not sure what the right fix is though.

@willnationsdev I imagine what's happening for your case is you probably need to write it like:

func _init(p_player="test3").(p_player):
  pass

otherwise it's going to call like this: I think
A._init() -> B._init("test3") -> B.Super._init("test3")

Edit:
The reason I think the suggestion above works is because you're trying to change the default value. If you weren't, you'd be doing the same thing I'm trying to do in the original issue.

NOTE:
I personally think the _init().() syntax is a bit annoying, and the _init method should probably just require ._init() (super) to be called inside it. but that's a different topic.

I tried to fix this for 3.1 but it wasn't as easy as I thought at first. Will try to review this soon.

For 4.0 we might try to change the syntax for calling the parent constructor (among other things). It's a big compatibility breakage but I think it's for the best.

Was this page helpful?
0 / 5 - 0 ratings