GDScript is an optionally typed language.
That means we can write code like this:
var name: String = "Godot"
var score: int = 100
var is_active: bool = true
var health: float = 100.0
var position: Vector2 = Vector2(100, 100)
This is good, because it reduces errors and documents our code.
However, this is a bit noisy. We already know "Godot"
is a string, 100
is an integer, and so on; we can see that. And GDScript knows it too.
So, the GDScript developpers gave us a nice shortcut; we can write this:
var name := "Godot"
var score := 100
var is_active := true
var health := 100.0
var position := Vector2(100, 100)
GDScript will guess the type of all those variables. This is called "type inference".
How does GDScript differentiate a float from an integer?Through convention, writing a plain number, like 0
, 15
, 300
, etc., is interpreted as an integer ( int
). Writing a number with a decimal point, like 0.0
, 15.0
, 300.0
, etc., is interpreted as a float ( float
).
Sometimes, you use an existing variable to let GDScript infer another variable. For example:
var my_variable_b := my_variable_a
In this example, my_variable_b
is inferred to be the same type as my_variable_a
. But if my_variable_a
is not typed, then my_variable_b
cannot be inferred, and you will get an error.
This is also true of expressions. The following code will result in an error:
var position := Vector2(100, 100)
var offset = Vector2(100, 100)
var final_position := position + offset
You're right, offset
isn't typed. We can fix this by adding the :
after the variable name:
var position := Vector2(100, 100)
var offset := Vector2(100, 100)
var final_position := position + offset
Inference is for you, not the engineWhen we talk of "type inference" and how GDScript guesses your types, it applies to the static code in the editor. It serves to write less text and get good autocompletion and errors.For the engine, there is no difference between writing types explicitly or not.
sometimes, Godot cannot guess the type of a variable. In those cases, we need to specify it ourselves.
For example, when nodes are in the scene, if you write:
var player := $MyCharacterBody2D
All Godot can infer is that it is a node of type Node
. It cannot know what type of node it is. So, we add a type hint to help Godot:
var player: CharacterBody2D = $MyCharacterBody2D
Another limitation is that some types are "nullable". That is, they can be null.
If in the example above, $MyCharacterBody2D
doesn't exist, then node
will be null
at runtime (but Godot won't give you an error in the editor).
So, in your head, you should read that node
type as " CharacterBody2D
or null
".
Any type can be null?No. Not all types are nullable. Built-in Godot primitives are not nullable: float
, int
, Vector2
, Vector2i
, Vector3
, Vector3i
, Color
, String
, bool
, and so on.
A last limitation is that some built-in methods do not specify their return type. For example, the round()
function can use either float
s, int
s, Vector2
s, or Vector3
s. As a result, GDScript cannot know the return type of round()
.
This line will give an error:
var rounded_vector := round(Vector2(22.84, 10.67))
(The Variant
type is a type that means "we don't know")
Instead, we have to explicitly type:
var rounded_vector: Vector2 = round(Vector2(22.84, 10.67))
You can use as
to cast a variable to a different type. For example:
var the_node := $MyCharacterBody2D as CharacterBody2D
This almost the same result as:
var the_node: CharacterBody2D = $MyCharacterBody2D
For example, to get good typing on some more generic variables:
func _on_body_entered(body: PhysicsBody2D) -> void:
if body is Player:
var player := body as Player
player.take_damage()
Yes, we could instead write var player: Player = body
, but using as
documents that we're converting a value from an unknown one to a known one.
as
also silently returns null
if a value cannot be converted, so it can be used as a guard:
func _on_body_entered(body: PhysicsBody2D) -> void:
var player := body as Player
if player != null:
player.take_damage()
We can also use this for casting elements that we do not want to put inside variables.
func _ready() -> void:
var timer: Timer = $MyTimerNode
timer.start()
func _ready() -> void:
($MyTimerNode as Timer).start()
See Also
Related terms in the Glossary