-
-
Notifications
You must be signed in to change notification settings - Fork 19.5k
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 cannot override Godot's native functions #55024
Comments
Seems to be related to: #40288 |
Shouldn't it be |
I expect to override any engine's function if I want to do it. Or at least the editor should tell me that I cannot override such functions and explain why. Another solution would be, having an empty object which hasn't had any functions but can be extended as a Singleton. |
I'm afraid that's not how things work, as it has probably been said in other issues, to achieve that the engine would have to use slow I remember that in Godot 3 so far, if you write a function with the same name as an existing function, Godot lets you "shadow" it, although it is not true overriding. For example if you write "get_position" in
So there should be a decision wether or not Godot should consider it an error. I personally think it should, but like many edge cases like this one, other people might have decided to exploit it and want it to remain maybe 🤷
I don't understand why you need an empty object or a singleton. |
It would be great to have an empty class, that you can use as a singleton so you can have any functions you want. That's the bare minimum to me. For example: extends EmptyObject
var __data = {}
func _ready():
set('random_key', 'random value')
func set(key, value):
print('Setting a new value')
__data[key] = value |
I still don't understand the relation with overriding functions, but you basically describe an utility class with static functions:
class_name Util
static func foo(a, b) -> int:
return a + b
func _ready():
print(Util.foo(3, 4)) And I dont understand the example you give with it... the example sounds like just a dictionary. var data = {}
data.set("hello", 42)
print(data.hello) And wanting both in the same object can be done with a dictionary inside an autoload. |
It has to have some custom code on Here a more complete code extends Node
var __global = {}
signal key_updated(name)
func _ready():
reset()
func reset():
# Load the default locale by default
set('locale', OS.get_locale().left(2))
set('soundfx_volume', 0.5)
set('music_volume', 0.5)
func set(key, value):
if __global.has(key):
logger.debug('Overtwriting key %s', [key])
else:
logger.debug('Writing key %s', [key])
__global[key] = value
emit_signal('key_updated', key)
func get(key, default_value = null):
return __global[key] if __global.has(key) else default_value |
And that example code doesn't work? It's basically still a fancy wrapped dictionary. You can put that in an autoload and it should work. Maybe the only difference is, with your code you'd have to call |
It doesn't because of the I understand, but prefixing any function with |
If you use basically: func _get(key):
if key == "foo":
return 42
I understand why you'd expect to do that with |
Still doesn't solve my naming issue. |
@akien-mga #54949 seems to concern member variables only, not functions, which are the problematic point here. |
You are supposed to override only virtual functions and they are all prefixed with |
Thank you for those explanations. However it would be better that behavior is describe somewhere (since it didn't behave that way in Godot 2/3), and also Godot itself should raise an error to warn the user. atm, this is not user friendly. |
I code like this:
It will report error: |
Another use case:
|
To repeat what @Zylann was explaining, not all functions in Godot can be overridden. That's the same in any language, some functions are virtual, others are not. In Godot's scripting API there's another level of indirection as some functions might be virtual in C++ but that doesn't transfer to the scripting API. "Virtual" methods are implemented by calling methods via StringName, which is much less efficient than what a C++ compiler can do for you with the virtual function table. So there's no intention to support overriding any method such as Now, we should indeed add explicit warnings whenever you shadow such a method unknowingly, as the way it behaves is not intuitive at all (and can still lead to bugs for internal engine calls using extends Control
var test = 0
func set(property, value):
print("Setting '%s' to '%s'." % [property, str(value)])
set(property, value)
func _ready():
test = 1
set("test", 2)
self.set("test", 3)
$".".set("test", 4)
call("set", "test", 5)
$".".call("set", "test", 6)
call_deferred("set", "test", 7)
$".".call_deferred("set", "test", 8)
get_script().set("test", 9) This prints:
IMO it's far from obvious, and not something we should aim to support. So I would ensure that shadowing an internal function raises a warning, as done in #54949 for variables. |
I think we have two options:
|
Whether you generally want to or not, if it was true overriding then the expectation from a programmer would be that the engine would call the override and not the original. Of course, not every public/exposed method is called by the engine, but some do, and consistency is expected. Allowing just shadowing wouldn't be very OOP of us, would it? And overrides in general are allowed, but we have strict rules that the method should be declared as virtual. It's just not all built-in methods are, for one reason or another (already explained in the discussion above). This is all completely within the OOP principles. |
Four Pillars of OOP: |
Reopening for now as #72487 was reverted. |
Consequences:
|
Yes, and this was never going to work correctly. |
Even though it did work as needed in 3.x. At this point it appears none of my 3.x apps, libraries, and tools are upgradable to 4.x. |
@tx350z It was a bug/inconsistency that you exploited |
In 3.x, this is also not overriding, but shadowing. You're just creating another method with the same name, which is definitely confusing. In 4.0, an additional problem is that even GDScript can't always distinguish between these methods. We could fix this, but it would hurt performance for no good reason, since the behavior in 3.x is still not correct and expected by users ("I've overridden Duplicate another my comment: Why it's done:
A few tips:
|
I think I found a solution for my needs in HxGodot. As much as I've come to love coding GDScript, the 4.0 update has too many new barriers to overcome. |
@GodotDevs it an always upcomming topic and you can see the useres want to have the possibility to override a core function. From technical perspective so far i anderstand, the core change in GdScript 2,0 is instead of calling functions by name you call it via function pointer. Why you not provide a |
@MikeSchulze Again, this didn't work in Godot 3.x either. It is not related to GDScript, it's just how Godot is, and always was. If a method is not made to be overridable, you can't override it, neither from scripting, nor from extensions. The only change in GDScript that is relevant here is that we now tell the user that what they are trying to do is wrong and is not going to work. There are no plans to allow overriding any core function, because it's impractical from the performance perspective. And once again, this is not a decision of the GDScript team, it's a core decision. Furthermore, cases like |
It is further confusing since the error message you get in 3.5 when you don't match the function signature is: Since we can only override virtual native methods, how do we know which native methods are virtual? |
Virtual methods all start with underscore ( |
Godot version
4.0.dev 7791599
System information
Linux binogure 5.14.0-2-amd64 #1 SMP Debian 5.14.9-2 (2021-10-03) x86_64 GNU/Linux
Issue description
I don't know if it is normal, but I cannot override any godot's native functions using GDScript.
It never calls the gdscript function but the godot's core function instead.
Steps to reproduce
The
set
function is never called, and there is no warning/error in godot explaining that is prohibited.Minimal reproduction project
No response
The text was updated successfully, but these errors were encountered: