static_typing.rst 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  1. .. _doc_gdscript_static_typing:
  2. Static typing in GDScript
  3. =========================
  4. In this guide, you will learn:
  5. - how to use static typing in GDScript;
  6. - that static types can help you avoid bugs;
  7. - that static typing improves your experience with the editor.
  8. Where and how you use this language feature is entirely up to you: you can use it
  9. only in some sensitive GDScript files, use it everywhere, or don't use it at all.
  10. Static types can be used on variables, constants, functions, parameters,
  11. and return types.
  12. A brief look at static typing
  13. -----------------------------
  14. With static typing, GDScript can detect more errors without even running the code.
  15. Also type hints give you and your teammates more information as you're working,
  16. as the arguments' types show up when you call a method. Static typing improves
  17. editor autocompletion and :ref:`documentation <doc_gdscript_documentation_comments>`
  18. of your scripts.
  19. Imagine you're programming an inventory system. You code an ``Item`` class,
  20. then an ``Inventory``. To add items to the inventory, the people who work with
  21. your code should always pass an ``Item`` to the ``Inventory.add()`` method.
  22. With types, you can enforce this:
  23. ::
  24. class_name Inventory
  25. func add(reference: Item, amount: int = 1):
  26. var item := find_item(reference)
  27. if not item:
  28. item = _instance_item_from_db(reference)
  29. item.amount += amount
  30. Static types also give you better code completion options. Below, you can see
  31. the difference between a dynamic and a static typed completion options.
  32. You've probably encountered a lack of autocomplete suggestions after a dot:
  33. .. figure:: img/typed_gdscript_code_completion_dynamic.webp
  34. :alt: Completion options for dynamic typed code.
  35. This is due to dynamic code. Godot cannot know what value type you're passing
  36. to the function. If you write the type explicitly however, you will get all
  37. methods, properties, constants, etc. from the value:
  38. .. figure:: img/typed_gdscript_code_completion_typed.webp
  39. :alt: Completion options for static typed code.
  40. .. tip::
  41. If you prefer static typing, we recommend enabling the
  42. **Text Editor > Completion > Add Type Hints** editor setting. Also consider
  43. enabling `some warnings <Warning system_>`_ that are disabled by default.
  44. .. UPDATE: Planned feature. If JIT/AOT are implemented, update this paragraph.
  45. Also, typed GDScript improves performance by using optimized opcodes when operand/argument
  46. types are known at compile time. More GDScript optimizations are planned in the future,
  47. such as JIT/AOT compilation.
  48. Overall, typed programming gives you a more structured experience. It
  49. helps prevent errors and improves the self-documenting aspect of your
  50. scripts. This is especially helpful when you're working in a team or on
  51. a long-term project: studies have shown that developers spend most of
  52. their time reading other people's code, or scripts they wrote in the
  53. past and forgot about. The clearer and the more structured the code, the
  54. faster it is to understand, the faster you can move forward.
  55. How to use static typing
  56. ------------------------
  57. To define the type of a variable, parameter, or constant, write a colon after the name,
  58. followed by its type. E.g. ``var health: int``. This forces the variable's type
  59. to always stay the same:
  60. ::
  61. var damage: float = 10.5
  62. const MOVE_SPEED: float = 50.0
  63. func sum(a: float = 0.0, b: float = 0.0) -> float:
  64. return a + b
  65. Godot will try to infer types if you write a colon, but you omit the type:
  66. ::
  67. var damage := 10.5
  68. const MOVE_SPEED := 50.0
  69. func sum(a := 0.0, b := 0.0) -> float:
  70. return a + b
  71. .. note::
  72. 1. There is no difference between ``=`` and ``:=`` for constants.
  73. 2. You don't need to write type hints for constants, as Godot sets it automatically
  74. from the assigned value. But you can still do so to make the intent of your code clearer.
  75. Also, this is useful for typed arrays (like ``const A: Array[int] = [1, 2, 3]``),
  76. since untyped arrays are used by default.
  77. What can be a type hint
  78. ~~~~~~~~~~~~~~~~~~~~~~~
  79. Here is a complete list of what can be used as a type hint:
  80. 1. ``Variant``. Any type. In most cases this is not much different from an untyped
  81. declaration, but increases readability. As a return type, forces the function
  82. to explicitly return some value.
  83. 2. *(Only return type)* ``void``. Indicates that the function does not return any value.
  84. 3. :ref:`Built-in types <doc_gdscript_builtin_types>`.
  85. 4. Native classes (``Object``, ``Node``, ``Area2D``, ``Camera2D``, etc.).
  86. 5. :ref:`Global classes <doc_gdscript_basics_class_name>`.
  87. 6. :ref:`Inner classes <doc_gdscript_basics_inner_classes>`.
  88. 7. Global, native and custom named enums. Note that an enum type is just an ``int``,
  89. there is no guarantee that the value belongs to the set of enum values.
  90. 8. Constants (including local ones) if they contain a preloaded class or enum.
  91. You can use any class, including your custom classes, as types. There are two ways
  92. to use them in scripts. The first method is to preload the script you want to use
  93. as a type in a constant:
  94. ::
  95. const Rifle = preload("res://player/weapons/rifle.gd")
  96. var my_rifle: Rifle
  97. The second method is to use the ``class_name`` keyword when you create.
  98. For the example above, your ``rifle.gd`` would look like this:
  99. ::
  100. class_name Rifle
  101. extends Node2D
  102. If you use ``class_name``, Godot registers the ``Rifle`` type globally in the editor,
  103. and you can use it anywhere, without having to preload it into a constant:
  104. ::
  105. var my_rifle: Rifle
  106. Specify the return type of a function with the arrow ``->``
  107. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  108. To define the return type of a function, write a dash and a right angle bracket ``->``
  109. after its declaration, followed by the return type:
  110. ::
  111. func _process(delta: float) -> void:
  112. pass
  113. The type ``void`` means the function does not return anything. You can use any type,
  114. as with variables:
  115. ::
  116. func hit(damage: float) -> bool:
  117. health_points -= damage
  118. return health_points <= 0
  119. You can also use your own classes as return types:
  120. ::
  121. # Adds an item to the inventory and returns it.
  122. func add(reference: Item, amount: int) -> Item:
  123. var item: Item = find_item(reference)
  124. if not item:
  125. item = ItemDatabase.get_instance(reference)
  126. item.amount += amount
  127. return item
  128. Covariance and contravariance
  129. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  130. When inheriting base class methods, you should follow the `Liskov substitution
  131. principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>`__.
  132. **Covariance:** When you inherit a method, you can specify a return type that is
  133. more specific (**subtype**) than the parent method.
  134. **Contravariance:** When you inherit a method, you can specify a parameter type
  135. that is less specific (**supertype**) than the parent method.
  136. Example:
  137. ::
  138. class_name Parent
  139. func get_property(param: Label) -> Node:
  140. # ...
  141. ::
  142. class_name Child extends Parent
  143. # `Control` is a supertype of `Label`.
  144. # `Node2D` is a subtype of `Node`.
  145. func get_property(param: Control) -> Node2D:
  146. # ...
  147. Specify the element type of an ``Array``
  148. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  149. To define the type of an ``Array``, enclose the type name in ``[]``.
  150. An array's type applies to ``for`` loop variables, as well as some operators like
  151. ``[]``, ``[...] =`` (assignment), and ``+``. Array methods
  152. (such as ``push_back``) and other operators (such as ``==``)
  153. are still untyped. Built-in types, native and custom classes,
  154. and enums may be used as element types. Nested array types (like ``Array[Array[int]]``)
  155. are not supported.
  156. ::
  157. var scores: Array[int] = [10, 20, 30]
  158. var vehicles: Array[Node] = [$Car, $Plane]
  159. var items: Array[Item] = [Item.new()]
  160. var array_of_arrays: Array[Array] = [[], []]
  161. # var arrays: Array[Array[int]] -- disallowed
  162. for score in scores:
  163. # score has type `int`
  164. # The following would be errors:
  165. scores += vehicles
  166. var s: String = scores[0]
  167. scores[0] = "lots"
  168. Since Godot 4.2, you can also specify a type for the loop variable in a ``for`` loop.
  169. For instance, you can write:
  170. ::
  171. var names = ["John", "Marta", "Samantha", "Jimmy"]
  172. for name: String in names:
  173. pass
  174. The array will remain untyped, but the ``name`` variable within the ``for`` loop
  175. will always be of ``String`` type.
  176. Specify the element type of a ``Dictionary``
  177. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  178. To define the type of a ``Dictionary``'s keys and values, enclose the type name in ``[]``
  179. and separate the key and value type with a comma.
  180. A dictionary's value type applies to ``for`` loop variables, as well as some operators like
  181. ``[]`` and ``[...] =`` (assignment). Dictionary methods that return values
  182. and other operators (such as ``==``) are still untyped. Built-in types, native
  183. and custom classes, and enums may be used as element types. Nested typed collections
  184. (like ``Dictionary[String, Dictionary[String, int]]``) are not supported.
  185. ::
  186. var fruit_costs: Dictionary[String, int] = { "apple": 5, "orange": 10 }
  187. var vehicles: Dictionary[String, Node] = { "car": $Car, "plane": $Plane }
  188. var item_tiles: Dictionary[Vector2i, Item] = { Vector2i(0, 0): Item.new(), Vector2i(0, 1): Item.new() }
  189. var dictionary_of_dictionaries: Dictionary[String, Dictionary] = { { } }
  190. # var dicts: Dictionary[String, Dictionary[String, int]] -- disallowed
  191. for cost in fruit_costs:
  192. # cost has type `int`
  193. # The following would be errors:
  194. fruit_costs["pear"] += vehicles
  195. var s: String = fruit_costs["apple"]
  196. fruit_costs["orange"] = "lots"
  197. Type casting
  198. ~~~~~~~~~~~~
  199. Type casting is an important concept in typed languages.
  200. Casting is the conversion of a value from one type to another.
  201. Imagine an ``Enemy`` in your game, that ``extends Area2D``. You want it to collide
  202. with the ``Player``, a ``CharacterBody2D`` with a script called ``PlayerController``
  203. attached to it. You use the ``body_entered`` signal to detect the collision.
  204. With typed code, the body you detect is going to be a generic ``PhysicsBody2D``,
  205. and not your ``PlayerController`` on the ``_on_body_entered`` callback.
  206. You can check if this ``PhysicsBody2D`` is your ``Player`` with the ``as`` keyword,
  207. and using the colon ``:`` again to force the variable to use this type.
  208. This forces the variable to stick to the ``PlayerController`` type:
  209. ::
  210. func _on_body_entered(body: PhysicsBody2D) -> void:
  211. var player := body as PlayerController
  212. if not player:
  213. return
  214. player.damage()
  215. As we're dealing with a custom type, if the ``body`` doesn't extend
  216. ``PlayerController``, the ``player`` variable will be set to ``null``.
  217. We can use this to check if the body is the player or not. We will also
  218. get full autocompletion on the player variable thanks to that cast.
  219. .. note::
  220. The ``as`` keyword silently casts the variable to ``null`` in case of a type
  221. mismatch at runtime, without an error/warning. While this may be convenient
  222. in some cases, it can also lead to bugs. Use the ``as`` keyword only if this
  223. behavior is intended. A safer alternative is to use the ``is`` keyword:
  224. ::
  225. if not (body is PlayerController):
  226. push_error("Bug: body is not PlayerController.")
  227. var player: PlayerController = body
  228. if not player:
  229. return
  230. player.damage()
  231. You can also simplify the code by using the ``is not`` operator:
  232. ::
  233. if body is not PlayerController:
  234. push_error("Bug: body is not PlayerController")
  235. Alternatively, you can use the ``assert()`` statement:
  236. ::
  237. assert(body is PlayerController, "Bug: body is not PlayerController.")
  238. var player: PlayerController = body
  239. if not player:
  240. return
  241. player.damage()
  242. .. note::
  243. If you try to cast with a built-in type and it fails, Godot will throw an error.
  244. .. _doc_gdscript_static_typing_safe_lines:
  245. Safe lines
  246. ^^^^^^^^^^
  247. You can also use casting to ensure safe lines. Safe lines are a tool to tell you
  248. when ambiguous lines of code are type-safe. As you can mix and match typed
  249. and dynamic code, at times, Godot doesn't have enough information to know if
  250. an instruction will trigger an error or not at runtime.
  251. This happens when you get a child node. Let's take a timer for example:
  252. with dynamic code, you can get the node with ``$Timer``. GDScript supports
  253. `duck-typing <https://stackoverflow.com/a/4205163/8125343>`__,
  254. so even if your timer is of type ``Timer``, it is also a ``Node`` and
  255. an ``Object``, two classes it extends. With dynamic GDScript, you also don't
  256. care about the node's type as long as it has the methods you need to call.
  257. You can use casting to tell Godot the type you expect when you get a node:
  258. ``($Timer as Timer)``, ``($Player as CharacterBody2D)``, etc.
  259. Godot will ensure the type works and if so, the line number will turn
  260. green at the left of the script editor.
  261. .. figure:: img/typed_gdscript_safe_unsafe_line.webp
  262. :alt: Unsafe vs Safe Line
  263. Unsafe line (line 7) vs Safe Lines (line 6 and 8)
  264. .. note::
  265. Safe lines do not always mean better or more reliable code. See the note above
  266. about the ``as`` keyword. For example:
  267. ::
  268. @onready var node_1 := $Node1 as Type1 # Safe line.
  269. @onready var node_2: Type2 = $Node2 # Unsafe line.
  270. Even though ``node_2`` declaration is marked as an unsafe line, it is more
  271. reliable than ``node_1`` declaration. Because if you change the node type
  272. in the scene and accidentally forget to change it in the script, the error
  273. will be detected immediately when the scene is loaded. Unlike ``node_1``,
  274. which will be silently cast to ``null`` and the error will be detected later.
  275. .. note::
  276. You can turn off safe lines or change their color in the editor settings.
  277. Typed or dynamic: stick to one style
  278. ------------------------------------
  279. Typed GDScript and dynamic GDScript can coexist in the same project. But
  280. it's recommended to stick to either style for consistency in your codebase,
  281. and for your peers. It's easier for everyone to work together if you follow
  282. the same guidelines, and faster to read and understand other people's code.
  283. Typed code takes a little more writing, but you get the benefits we discussed
  284. above. Here's an example of the same, empty script, in a dynamic style:
  285. ::
  286. extends Node
  287. func _ready():
  288. pass
  289. func _process(delta):
  290. pass
  291. And with static typing:
  292. ::
  293. extends Node
  294. func _ready() -> void:
  295. pass
  296. func _process(delta: float) -> void:
  297. pass
  298. As you can see, you can also use types with the engine's virtual methods.
  299. Signal callbacks, like any methods, can also use types. Here's a ``body_entered``
  300. signal in a dynamic style:
  301. ::
  302. func _on_area_2d_body_entered(body):
  303. pass
  304. And the same callback, with type hints:
  305. ::
  306. func _on_area_2d_body_entered(body: PhysicsBody2D) -> void:
  307. pass
  308. Warning system
  309. --------------
  310. .. note::
  311. Detailed documentation about the GDScript warning system has been moved to
  312. :ref:`doc_gdscript_warning_system`.
  313. Godot gives you warnings about your code as you write it. The engine identifies
  314. sections of your code that may lead to issues at runtime, but lets you decide
  315. whether or not you want to leave the code as it is.
  316. We have a number of warnings aimed specifically at users of typed GDScript.
  317. By default, these warnings are disabled, you can enable them in Project Settings
  318. (**Debug > GDScript**, make sure **Advanced Settings** is enabled).
  319. You can enable the ``UNTYPED_DECLARATION`` warning if you want to always use
  320. static types. Additionally, you can enable the ``INFERRED_DECLARATION`` warning
  321. if you prefer a more readable and reliable, but more verbose syntax.
  322. ``UNSAFE_*`` warnings make unsafe operations more noticeable, than unsafe lines.
  323. Currently, ``UNSAFE_*`` warnings do not cover all cases that unsafe lines cover.
  324. Common unsafe operations and their safe counterparts
  325. ----------------------------------------------------
  326. ``UNSAFE_PROPERTY_ACCESS`` and ``UNSAFE_METHOD_ACCESS`` warnings
  327. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  328. In this example, we aim to set a property and call a method on an object
  329. that has a script attached with ``class_name MyScript`` and that ``extends
  330. Node2D``. If we have a reference to the object as a ``Node2D`` (for instance,
  331. as it was passed to us by the physics system), we can first check if the
  332. property and method exist and then set and call them if they do:
  333. ::
  334. if "some_property" in node_2d:
  335. node_2d.some_property = 20 # Produces UNSAFE_PROPERTY_ACCESS warning.
  336. if node_2d.has_method("some_function"):
  337. node_2d.some_function() # Produces UNSAFE_METHOD_ACCESS warning.
  338. However, this code will produce ``UNSAFE_PROPERTY_ACCESS`` and
  339. ``UNSAFE_METHOD_ACCESS`` warnings as the property and method are not present
  340. in the referenced type - in this case a ``Node2D``. To make these operations
  341. safe, you can first check if the object is of type ``MyScript`` using the
  342. ``is`` keyword and then declare a variable with the type ``MyScript`` on
  343. which you can set its properties and call its methods:
  344. ::
  345. if node_2d is MyScript:
  346. var my_script: MyScript = node_2d
  347. my_script.some_property = 20
  348. my_script.some_function()
  349. Alternatively, you can declare a variable and use the ``as`` operator to try
  350. to cast the object. You'll then want to check whether the cast was successful
  351. by confirming that the variable was assigned:
  352. ::
  353. var my_script := node_2d as MyScript
  354. if my_script != null:
  355. my_script.some_property = 20
  356. my_script.some_function()
  357. ``UNSAFE_CAST`` warning
  358. ~~~~~~~~~~~~~~~~~~~~~~~
  359. In this example, we would like the label connected to an object entering our
  360. collision area to show the area's name. Once the object enters the collision
  361. area, the physics system sends a signal with a ``Node2D`` object, and the most
  362. straightforward (but not statically typed) solution to do what we want could
  363. be achieved like this:
  364. ::
  365. func _on_body_entered(body: Node2D) -> void:
  366. body.label.text = name # Produces UNSAFE_PROPERTY_ACCESS warning.
  367. This piece of code produces an ``UNSAFE_PROPERTY_ACCESS`` warning because
  368. ``label`` is not defined in ``Node2D``. To solve this, we could first check if the
  369. ``label`` property exist and cast it to type ``Label`` before settings its text
  370. property like so:
  371. ::
  372. func _on_body_entered(body: Node2D) -> void:
  373. if "label" in body:
  374. (body.label as Label).text = name # Produces UNSAFE_CAST warning.
  375. However, this produces an ``UNSAFE_CAST`` warning because ``body.label`` is of a
  376. ``Variant`` type. To safely get the property in the type you want, you can use the
  377. ``Object.get()`` method which returns the object as a ``Variant`` value or returns
  378. ``null`` if the property doesn't exist. You can then determine whether the
  379. property contains an object of the right type using the ``is`` keyword, and
  380. finally declare a statically typed variable with the object:
  381. ::
  382. func _on_body_entered(body: Node2D) -> void:
  383. var label_variant: Variant = body.get("label")
  384. if label_variant is Label:
  385. var label: Label = label_variant
  386. label.text = name
  387. Cases where you can't specify types
  388. -----------------------------------
  389. .. UPDATE: Not supported. If nested types are supported, update this section.
  390. To wrap up this introduction, let's mention cases where you can't use type hints.
  391. This will trigger a **syntax error**.
  392. 1. You can't specify the type of individual elements in an array or a dictionary:
  393. ::
  394. var enemies: Array = [$Goblin: Enemy, $Zombie: Enemy]
  395. var character: Dictionary = {
  396. name: String = "Richard",
  397. money: int = 1000,
  398. inventory: Inventory = $Inventory,
  399. }
  400. 2. Nested types are not currently supported:
  401. ::
  402. var teams: Array[Array[Character]] = []
  403. Summary
  404. -------
  405. .. UPDATE: Planned feature. If more optimizations (possibly JIT/AOT?) are
  406. .. implemented, update this paragraph.
  407. Typed GDScript is a powerful tool. It helps you write more structured code,
  408. avoid common errors, and create scalable and reliable systems. Static types
  409. improve GDScript performance and more optimizations are planned for the future.