godot: GDScript 2.0: Variant type errors
Godot version
v4.0.stable.official [92bee43ad]
System information
Windows 10, MacOs
Issue description
I encountered this problem by recording a use case for a bug report. And was very surprised that I did not see these errors before. Why are the addons peer default excluded from script validation? I think many don’t know this, I was also very surprised when I found this option.
The compiler shows some errors, but this should not be an error or a warning
The variable type is being inferred from a Variant value, so it will be typed as Variant. (Warning treated as error.)
Steps to reproduce
put this code in a fresh script under the root folder
extends Node
func callable_return_type(clazz :Callable):
var value := clazz.call()
func meta_variant():
var value := Engine.get_meta("value")
func array_variant():
var store :Array[Variant] = []
var value := store.pop_front()
func foo() -> Variant:
return ""
func return_type_variant():
var value := foo()
Row 5:The variable type is being inferred from a Variant value, so it will be typed as Variant. (Warning treated as error.)
Row 9:The variable type is being inferred from a Variant value, so it will be typed as Variant. (Warning treated as error.)
Row 14:The variable type is being inferred from a Variant value, so it will be typed as Variant. (Warning treated as error.)
Row 21:The variable type is being inferred from a Variant value, so it will be typed as Variant. (Warning treated as error.)
For the Callable example, I would say that the error/warning is correct.
It’s just that Callable has no type information, it should be improved as it was done for Array
For all the other errors it should be corret, the return type is defined as Variant
Minimal reproduction project
N/A
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 22 (13 by maintainers)
The exclude addons setting is meant to end users to not have to see a bunch of warnings that come from the addons they use, since often those come from a third-party.
Regarding inference on Variant, it is done on purpose as said before. The fact that you are relying on a function that returns Variant for your static typing can be very problematic, since it can easily not be your intention.
Usually you use a static type to restrict what can be stored in the variable, and type inference is just meant to omit redundancy when the type is obvious from the default value. Variant is most often not an obvious return type. So if you are using static type to not restrict the type (by using Variant) you have to tell so explicitly, because type inference is probably a mistake for this case. Or not use a static type at all, which behaves the same. The
Variantis not really a type, it’s just a explicit way to tell when there’s no type restriction, it is not supposed to be used implicitly.Your
Callable.call()example is a good showcase on how this can be done accidentally. One may think the Callable is retaining information about its bound function and restricting to its return type, but it does not and only use the generic Callable interface, which returns Variant.If you don’t want this behavior you can either use the
@warning_ignoreannotation or disable it for the project.Everything can be changed. This is a new thing in Godot 4.0 which was just released, so it will take time until we understand the full implication of this to all users.
I still prefer to make it an error by default and annoy some users than the opposite and have users introduce subtle issues without realizing. But if most users do expect this as a valid behavior we can change it to warn or ignore by default.
I personally do find odd to infer
Variantbecause it’s not a type (i.e. there is no value forxthat would makex is Variantto returntrue, if that was a valid check, unless we hardcoded it to always betrue). But everything is up to discussion and I’m open to listen to arguments.I proposed adding a note to this in the documentation (#6934). I believe this report is now resolved. Anyone is free to create a proposal or discussion to ask for a change in the defaults.
The main problem is that GDScript is not a strongly statically typed language. It can be used in dynamic style, static style, or even a combination of the two (although we recommend sticking to one style within a project).
=and:=are too similar to each other, so we can’t always tell if it’s a mistake or the preffered style. But we want to help users avoid mistakes when we see that they are probably doing something weird.You can disable the warning in your project and use whatever style you want. Of course, if you are developing a plugin, you should also consider that user preferences may differ from yours. And it may be less convenient for you if you want your plugin to be compatible with as many projects as possible. The alternatives have already been mentioned above: 1. use
=instead of:=(forVariantit’s the same in practice), or 2. specify theVarianttype explicitly.Note that even if we change the default level from “Error” to “Warn”, little will change for you as the plugin developer: you can still expect the user to switch the level to “Error” (since you expect the user to disable the “Exclude Addons” checkbox).
It’s not treated as an error, it’s a warning, because it points at a potential issue. Basically, having Variant as a return type for explicitness does make sense, but using Variant as a type hint for a variable doesn’t, because everything is a Variant, and that just means it’s not actually typed.
As far as I understand it, in the case of
Variantyou should specify the type explicitly (var a: Variant = get_variant(), or you can simplevar a = get_variant()) and not rely on type inference to avoid possible errors.Variantis not a separate type, it is an indication that the value can be of any type.Varianthas a few exceptions that distinguish it from other explicit types (for example, a variable of typeArray(Array[Variant]) can refer toArray[int], although this is unsafe).Thanks to all who took the time to discuss this. Let’s see what time brings 😉
All warnings in plugins are ignored by default.
(But you should still avoid warnings.)
This is intentional, as far as I remember. See #72608.