c++ has constructors so shouldn't we avoid using _init in gdnative?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By thenegativehunter

c++ has constructors.
_init is for gdnative to fill that hole…
also when you override something c++ you just redefine what it does. but in gdscript you add to what it does, the overriden function gets called first.
so basically overriding _init is the same as constructor of a deriving class in c++.

So what is the concrete question?

In current implementation 3.X (what will change in 4.0, at least for c++) you have to use _init() as ctor, or as a addition to them, but you can’t really override them, since gdnative classes aren’t Godot’s core classes, but rather a wrappers (with kind of complicated marshaling).

sash-rc | 2021-08-22 15:47

:bust_in_silhouette: Reply From: Zylann

C++ constructors construct a class. But in current C++ bindings, classes are actually wrappers around an existing Godot object. It is not true inheritance. It cannot be, because Godot exposes a C API, and C does not know what a class is.

So every class has to contain an additional field, which points to the Godot object it extends. This pointer needs to be initialized.

Problem: from what I recall, in a constructor without argument, there is no way to have this field initialized “automagically”. This means you can’t call Godot functions from it, at all. It would crash.
A solution would be to require every constructor to accept that pointer as argument, and also require them to call their parent constructor with that pointer. It’s a bit tedious though. Also, parameterless constructors would not be allowed, for the same reason.

But there is another problem: wrappers for Godot classes or your own sometimes need to get created, but not necessarily by your code, and not for the same reason. If a script passes you a Sprite, the Sprite already exists. But the object representing that Sprite in your library isn’t, and gets created on the fly behinds the scenes. That means if you were to use new Sprite(), it won’t actually create the sprite. It will only create a “Sprite wrapper”. If it was also creating the underlying Godot object, then the mechanism I described earlier would fail, as passing an existing sprite for the first time into one of your functions would end up creating a new one instead.

So… it was decided that creating instances was done with Class::_new() instead of new, and that _init() be created in addition to the C++ constructor to allow you to call functions of the extended object (mimicking GDScript).
Note, you can actually write code in the constructor. But calling Godot functions from there will crash.
In theory _init could also be made optional, in the cases you don’t need it. The library would have to somehow find a way to make sure it fallbacks on a no-op, instead of calling the ill-formed Object::_init() at the moment. It might be a bit error prone though.


About overriding: I didn’t experiment much with this on the C++ bindings, mostly because I don’t code this way much, but the same issue might be at stake: classes are C++ wrappers, they are not the true ones. So virtuality doesn’t cross boundaries.
I’m not sure which override you want to achieve, but if you mean in the C++ sense, it needs the overriden function to have the virtual keyword if you want polymorphism to work. But again, that essentially won’t work this way with Godot object functions.