godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.15k stars 97 forks source link

`is_instance_of` function should be accessible from godot-cpp, not only from gdscript #10514

Open funatsufumiya opened 2 months ago

funatsufumiya commented 2 months ago

Describe the project you are working on

A 2D Game. Physically interactive contents for public facilities.

Describe the problem or limitation you are having in your project

is_instance_of function cannot be used in directly godot-cpp. This is terrible when creating some kind of GDExtension, with comparing nodes, classes and scripts. (For example: https://github.com/funatsufumiya/godot_finder)

Describe the feature / enhancement and how it helps to overcome the problem or limitation

Make is_instance_of function accesible not only from GDScript, even in godot-cpp.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

You can check a node is whether instance of some GDNativeClass or Script class, even in GDExtension.

Without is_instance_of function, you cannot exactlly check or compare a node, is whether instance of some GDNativeClass or Script class, without GDScript.

If this enhancement will not be used often, can it be worked around with a few lines of script?

this code partially emulates the behavior of is_instance_of, but not perfect.

GDExtension now cannot achieve the perfect behavior of is_instance_of without this proposal.

Is there a reason why this should be core and not an add-on in the asset library?

GDExtension now cannot achieve this without this proposal.

AThousandShips commented 2 months ago

See also:

AThousandShips commented 2 months ago

Now this exact method can't be extended to extensions or godot-cpp, as there's no general way to provide a type as an argument

Dor the class check this would be pretty much covered by the above IMO, for checking variant types you can just check with variant itself

dsnopek commented 2 months ago

In godot-cpp, the currently recommended way to check if an object is of a particular class is by using Object::cast_to<T>(obj) and checking if the result is nullptr or not.

This is also what a lot of module code in Godot itself does, and godot-cpp aims to provide a similar experience.

However, I don't really know how we'd bring scripts into this, because from the perspective of GDExtension, scripts aren't types. I'd love to see some example code from a project that is treating scripts as types, and see exactly what it is trying to accomplish. That would help me understand what you're looking for.

funatsufumiya commented 2 months ago

Thank you for the response.

The situation I am thinking of is that, a type is given as GDNativeClass or Script (or String / StringName) from GDScript and I want to determine if an object is of that type.

Object::cast_to(obj) and checking if the result is nullptr or not

This is available when T is specifically given, but when type is given from script, T cannot be exact.

All I need is to determine if a node is a specific type, such as Sprite2D, or a user type defined in a script, such as Player. My point is that godot-cpp has no way to check exact the type given arbitrarily from GDScript.

dalexeev commented 2 months ago

Note that since 4.3 you can get is_instance_of() as a Callable from GDScript. You can pass it to other languages ​​too.

@tool
extends EditorScript

func get_is_instance_of() -> Callable:
    return is_instance_of

func _run() -> void:
    print(get_is_instance_of().call(self, EditorScript)) # true
    print(get_is_instance_of().call(self, Node)) # false

However, note that Godot currently does not have first-class types (i.e. types to represent types). GDScript uses a GDScriptNativeClass wrapper to represent native classes. This is the main reason why is_instance_of() only exists in @GDScript, not in @GlobalScope.

funatsufumiya commented 2 months ago

@dalexeev Thank you. I understood reasons why is_instance_of not impremented in godot-cpp.

Main case I thought was interop between GDScript and C++, I'll use GDScript Callable wrapper as for now.