-
-
Notifications
You must be signed in to change notification settings - Fork 21.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GDScript: Fix some methods still can use multi-level calls #81139
base: master
Are you sure you want to change the base?
GDScript: Fix some methods still can use multi-level calls #81139
Conversation
b92386b
to
5e081e4
Compare
Can someone explain to me what bug this is solving in a game? |
This fixes an inconsistency in GDScript. All other methods require an explicit |
CC @Sauermann I think either we should treat all script classes as one or it should be explicitly documented that We could also add func _notification2(what: int, reversed: bool) -> void:
if not reversed:
super(what, reversed)
# ...this level...
if reversed:
super(what, reversed) |
|
But it can easily be achieved without multi-level calls, just one line needs to be changed. Unlike func _get_property_list() -> Array[Dictionary]:
var result := super() # Instead of `var result: Array[Dictionary] = []`.
result.append({name = "property", type = TYPE_INT})
return result Yes, |
My argument is not about compatibility. The order of registering properties in the engine is important. It's not something that users should be able to break. This method is an exception because extending classes should not be able to override the behavior of the extended class. It's just something that should never happen. I'm saying this about the logic of this call in the engine overall, not just in GDScript. These methods and the way they are called is important to the core. So yeah, nuance matters more than perceived consistency. |
Okay, I got your point. Then I think all exceptions with multi-level calls (currently 2 methods) should be justified, commented in the code and documented. |
5e081e4
to
3f5fe42
Compare
3f5fe42
to
0b09512
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Went through it code and I believe all of this makes sense. Certain functions were not returning inside a while
loop, meaning even after finding a result, superclass methods were being called.
This might actually end up fixing a few unexpected/awkward behaviors.
I have some minor requests, but nothing that fundamentally changes the opinion that this should be merged :)
Does super() exist in c++ modules or gdextension? I think we have to do call("super") right? Not sure the syntax. |
No, |
@YuriSizov I'm still unsure about Also unusual is that if I also checked our codebase and found that most of the time we don't call the base class method (it called automatically?). However, there are multiple instances of a (wrong?) call to the base method:
|
@dalexeev So the thing is, all of these methods are ML calls in the engine. You can check the I think it's reasonable that extensions and scripting work in the exactly same way as the engine. So if the core method is ML, then GDScript should do the same thing in its class inheritance chain. Otherwise we have to deal with different expectations between the engine core and engine extensions. I was mainly advocating for Ideally, though, this should be consistent with core, IMO. Maybe @vnen can offer an opinion before we move forward with any specific changes, since he'd be well-versed in both core and GDScript. |
0b09512
to
cdec343
Compare
cdec343
to
cdc63a3
Compare
IMO all of those make sense to be multilevel, except For something like While dynamic properties are already tricky to deal with in OOP, it shouldn't break polymorphism. So a sub class should not just overwrite the properties of the super class by overriding this behavior, which would be the main reason to make those not multilevel and force the use of Lastly, I think that if one of the property-related methods is ML, all of them should be, otherwise we'll have to keep remembering which ones are. |
Post-poned the target release of this PR to 4.3 as there's ongoing discussion. |
@@ -154,6 +154,7 @@ | |||
[/codeblocks] | |||
[b]Note:[/b] This method is intended for advanced purposes. For most common use cases, the scripting languages offer easier ways to handle properties. See [annotation @GDScript.@export], [annotation @GDScript.@export_enum], [annotation @GDScript.@export_group], etc. | |||
[b]Note:[/b] If the object's script is not [annotation @GDScript.@tool], this method will not be called in the editor. | |||
[b]Note:[/b] [code]_get_property_list()[/code] is automatically called for [b]all[/b] base classes. Unlike most other methods, you don't need to call [code]super()[/code] (in GDScript). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[b]Note:[/b] [code]_get_property_list()[/code] is automatically called for [b]all[/b] base classes. Unlike most other methods, you don't need to call [code]super()[/code] (in GDScript). | |
[b]Note:[/b] [method _get_property_list] is automatically called for [b]all[/b] inherited classes. Unlike most other methods, you do not need to call [code]super()[/code] (in GDScript). |
@@ -185,6 +186,7 @@ | |||
[/csharp] | |||
[/codeblocks] | |||
[b]Note:[/b] The base [Object] defines a few notifications ([constant NOTIFICATION_POSTINITIALIZE] and [constant NOTIFICATION_PREDELETE]). Inheriting classes such as [Node] define a lot more notifications, which are also received by this method. | |||
[b]Note:[/b] [code]_notification()[/code] is automatically called for [b]all[/b] base classes. Unlike most other methods, you don't need to call [code]super()[/code] (in GDScript). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[b]Note:[/b] [code]_notification()[/code] is automatically called for [b]all[/b] base classes. Unlike most other methods, you don't need to call [code]super()[/code] (in GDScript). | |
[b]Note:[/b] [method _notification] is automatically called for [b]all[/b] inherited classes. Unlike most other methods, you do not need to call [code]super()[/code] (in GDScript). |
In 4.0 we removed multi-level calls, users must now always explicitly use
super()
to call a base class method.However, some methods are not implemented correctly, and a base class method may be implicitly called (if child class method returns
false
,null
, or an error occurs).This is most apparent in_get_property_list()
and_notification()
, which are always multi-level called.Outdated example
Prints:
Method list:
_set()
_get()
_validate_property()
(!)_get_property_list()
_property_can_revert()
_property_get_revert()
(!)_notification()
_to_string()
EDIT 1. Formally, this doesn't break compatibility, it's a bug fix. But some users can rely on this wrong behavior (I believe this is a bug), so it definitely deserves a mention in the release notes if this PR gets merged.
EDIT 2.
_notification()
looks problematic, sincenotification()
is essentially intended for multi-level calls. See comment below.