-
-
Notifications
You must be signed in to change notification settings - Fork 21.1k
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
Statically typed function argument silently converted to null if the type doesn't match #37312
Comments
@dalexeev Maybe you misunderstood. I'm not trying to fix my example code. I'm trying to say there's an obvious bug in the example code, and not only does the static typing fail to catch it, it's actually altering behaviour of the code at runtime. |
Yes, you are right, at runtime this should cause an error. Just the issue title is a bit confusing. |
Ideally, at runtime, when the script gets parsed (as opposed to being run), to be even more precise ;) |
I am not sure that this analysis is possible even for local variables (and even more so for class members). func _run():
var bar = "hello"
if randi() % 2:
bar = Node.new()
foo(bar) # What type of `bar` is it now?
func foo(bar: Node):
... The only way is to check the type at the time of calling Another thing is if the |
Oh, I was referring to a situation like this: func _run():
var bar := "hello"
print("bar outside foo: ", bar) # prints "hello"
foo(bar) If not typed then yeah it can only defer to runtime (and induce a cost). |
I'm going to look at making a PR now, and if it turns out to be over my head I'll post back here. |
Colour me surprised: this behaviour is coded explicitly. godot/modules/gdscript/gdscript_function.cpp Lines 339 to 349 in a2da99f
Paraphrasing: whenever the actual argument isn't convertible to the expected type, rather than immediately giving up with an error, we first check whether This was added in f0efc75 because "Previous version resulted in confusing (but actually right) errors". Fair enough, but now it results in confusing (and actually wrong) runtime behaviour. But there is some good news: the error message seems to have improved since that commit was written, so it may no longer be necessary. Here's my testing code: extends Node
func _ready():
# Using call_deferred to avoid stopping at the first error.
call_deferred("foo", Node.new()) # Correct type (Node)
call_deferred("foo", Node2D.new()) # Correct type (Node subclass)
call_deferred("foo", RegEx.new()) # Object type, but not a Node
call_deferred("foo", "hello") # String type
call_deferred("foo", []) # Array type
call_deferred("foo", null) # null type
# Using an extra level of indirection through this untyped `foo` because
# call_deferred seems to silently ignore invocations with the wrong signature.
func foo(bar):
print("bar inside foo: ", bar)
foo_impl(bar)
func foo_impl(bar: Node):
print("bar inside foo_impl: ", bar) And the resulting output, when I run this in a build with f0efc75 reverted:
Those look like fine error messages to me! @bojidar-bg Would you agree to a pull request to revert that commit? |
This is actually convenient. In my case I have a Player class and in various methods I do this:
I would be sad if this gave an error :I |
https://xkcd.com/1172/ is just too true, isn't it... But seriously, this auto-nulling behaviour is undocumented, inconsistent (it doesn't happen if you have |
Godot version:
3.2.1.stable.official
OS/device including version:
Arch Linux (installed
godot-bin
from AUR)Issue description:
Static typing on function arguments can under some circumstances result in an argument silently being converted to
null
when the type doesn't match, rather than throwing an error.Steps to reproduce:
Just paste the above code into a new GDScript file and hit Ctrl+Shift+X to run it.
Expected result:
Because
bar
has no type, the error can't be detected at compile time. So I would expect an error at runtime like this:Alternatively, the
bar
variable should have theString
value of"hello"
inside the functionfoo
, as would happen if there weren't any type annotations present:This would be a worse outcome than a clear error, but I could understand it from a performance point of view if dynamic types aren't checked at every possible occasion.
Actual result:
No errors are reported; the function is called successfully but the incoming argument is mutilated into
null
:Interestingly, the error is reported correctly if I change the function to take
Array
instead ofNode
:Minimal reproduction project:
Copy-pasting the one snippet above is sufficient.
The text was updated successfully, but these errors were encountered: