static_typing.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. .. _doc_gdscript_static_typing:
  2. Static typing in GDScript
  3. =========================
  4. In this guide, you will learn:
  5. - **How to use types in GDScript**
  6. - That **static types can help you avoid bugs**
  7. Where and how you use this new language feature is entirely up to you:
  8. you can use it only in some sensitive GDScript files, use it everywhere,
  9. or write code like you always did!
  10. Static types can be used on variables, constants, functions, parameters,
  11. and return types.
  12. .. note::
  13. Typed GDScript is available since Godot 3.1.
  14. A brief look at static typing
  15. -----------------------------
  16. With typed GDScript, Godot can detect even more errors as you write
  17. code! It gives you and your teammates more information as you’re
  18. working, as the arguments’ types show up when you call a method.
  19. Imagine you’re programming an inventory system. You code an ``Item``
  20. node, then an ``Inventory``. To add items to the inventory, the people
  21. who work with your code should always pass an ``Item`` to the
  22. ``Inventory.add`` method. With types, you can enforce this:
  23. ::
  24. # In Item.gd
  25. class_name Item
  26. # In Inventory.gd
  27. class_name Inventory
  28. func add(reference: Item, amount: int = 1):
  29. var item = find_item(reference)
  30. if not item:
  31. item = _instance_item_from_db(reference)
  32. item.amount += amount
  33. Another significant advantage of typed GDScript is the new **warning
  34. system**. From version 3.1, Godot gives you warnings about your code as
  35. you write it: the engine identifies sections of your code that may lead
  36. to issues at runtime, but lets you decide whether or not you want to
  37. leave the code as it is. More on that in a moment.
  38. Static types also give you better code completion options. Below, you
  39. can see the difference between a dynamic and a static typed completion
  40. options for a class called ``PlayerController``.
  41. You’ve probably stored a node in a variable before, and typed a dot to
  42. be left with no autocomplete suggestions:
  43. .. figure:: ./img/typed_gdscript_code_completion_dynamic.png
  44. :alt: code completion options for dynamic
  45. This is due to dynamic code. Godot cannot know what node or value type
  46. you’re passing to the function. If you write the type explicitly
  47. however, you will get all public methods and variables from the node:
  48. .. figure:: ./img/typed_gdscript_code_completion_typed.png
  49. :alt: code completion options for typed
  50. In the future, typed GDScript will also increase code performance:
  51. Just-In-Time compilation and other compiler improvements are already
  52. on the roadmap!
  53. Overall, typed programming gives you a more structured experience. It
  54. helps prevent errors and improves the self-documenting aspect of your
  55. scripts. This is especially helpful when you’re working in a team or on
  56. a long-term project: studies have shown that developers spend most of
  57. their time reading other people’s code, or scripts they wrote in the
  58. past and forgot about. The clearer and the more structured the code, the
  59. faster it is to understand, the faster you can move forward.
  60. How to use static typing
  61. ------------------------
  62. To define the type of a variable or a constant, write a colon after the
  63. variable’s name, followed by its type. E.g. ``var health: int``. This
  64. forces the variable's type to always stay the same:
  65. ::
  66. var damage: float = 10.5
  67. const MOVE_SPEED: float = 50.0
  68. Godot will try to infer types if you write a colon, but you omit the
  69. type:
  70. ::
  71. var life_points := 4
  72. var damage := 10.5
  73. var motion := Vector2()
  74. Currently you can use three types of… types:
  75. 1. `Built-in
  76. types <http://docs.godotengine.org/en/3.0/getting_started/scripting/gdscript/gdscript_basics.html#built-in-types>`__
  77. 2. Core classes and nodes (``Object``, ``Node``, ``Area2D``,
  78. ``Camera2D``, etc.)
  79. 3. Your own, custom classes. Look at the new
  80. `class_name <https://godot.readthedocs.io/en/latest/getting_started/step_by_step/scripting_continued.html#register-scripts-as-classes>`__
  81. feature to register types in the editor.
  82. .. note::
  83. You don't need to write type hints for constants, as Godot sets it automatically from the assigned value. But you can still do so to make the intent of your code clearer.
  84. Custom variable types
  85. ~~~~~~~~~~~~~~~~~~~~~
  86. You can use any class, including your custom classes, as types. There
  87. are two ways to use them in scripts. The first method is to preload the
  88. script you want to use as a type in a constant:
  89. ::
  90. const Rifle = preload('res://player/weapons/Rifle.gd')
  91. var my_rifle: Rifle
  92. The second method is to use the ``class_name`` keyword when you create.
  93. For the example above, your Rifle.gd would look like this:
  94. ::
  95. extends Node2D
  96. class_name Rifle
  97. If you use ``class_name``, Godot registers the Rifle type globally in
  98. the editor, and you can use it anywhere, without having to preload it
  99. into a constant:
  100. ::
  101. var my_rifle: Rifle
  102. Variable casting
  103. ~~~~~~~~~~~~~~~~
  104. Type casting is a key concept in typed languages.
  105. Casting is the conversion of a value from one type to another.
  106. Imagine an Enemy in your game, that ``extends Area2D``. You want it to
  107. collide with the Player, a ``KinematicBody2D`` with a script called
  108. ``PlayerController`` attached to it. You use the ``on_body_entered``
  109. signal to detect the collision. With typed code, the body you detect is
  110. going to be a generic ``PhysicsBody2D``, and not your
  111. ``PlayerController`` on the ``_on_body_entered`` callback.
  112. You can check if this ``PhysicsBody2D`` is your Player with the ``as``
  113. casting keyword, and using the colon ``:`` again to force the variable
  114. to use this type. This forces the variable to stick to the
  115. ``PlayerController`` type:
  116. ::
  117. func _on_body_entered(body: PhysicsBody2D) -> void:
  118. var player := body as PlayerController
  119. if not player:
  120. return
  121. player.damage()
  122. As we’re dealing with a custom type, if the ``body`` doesn’t extend
  123. ``PlayerController``, the ``player``\ variable will be set to ``null``.
  124. We can use this to check if the body is the player or not. We will also
  125. get full autocompletion on the player variable thanks to that cast.
  126. .. note::
  127. If you try to cast with a built-in type and it fails, Godot will throw an error.
  128. Safe lines
  129. ^^^^^^^^^^
  130. You can also use casting to ensure safe lines. Safe lines are a new
  131. tool in Godot 3.1 to tell you when ambiguous lines of code are
  132. type-safe. As you can mix and match typed and dynamic code, at times,
  133. Godot doesn’t have enough information to know if an instruction will trigger
  134. an error or not at runtime.
  135. This happens when you get a child node. Let’s take a timer for example:
  136. with dynamic code, you can get the node with ``$Timer``. GDScript
  137. supports `duck-typing <https://stackoverflow.com/a/4205163/8125343>`__,
  138. so even if your timer is of type ``Timer``, it is also a ``Node`` and an
  139. ``Object``, two classes it extends. With dynamic GDScript, you also
  140. don’t care about the node’s type as long as it has the methods you need
  141. to call.
  142. You can use casting to tell Godot the type you expect when you get a
  143. node: ``($Timer as Timer)``, ``($Player as KinematicBody2D)``, etc.
  144. Godot will ensure the type works and if so, the line number will turn
  145. green at the left of the script editor.
  146. .. figure:: ./img/typed_gdscript_safe_unsafe_line.png
  147. :alt: Safe vs Unsafe Line
  148. Safe vs Unsafe Line
  149. .. note::
  150. You can turn off safe lines or change their color in the editor settings.
  151. Define the return type of a function with the arrow ->
  152. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  153. To define the return type of a function, write a dash and a right angle
  154. bracket ``->`` after it’s declaration, followed by the return type:
  155. ::
  156. func _process(delta: float) -> void:
  157. pass
  158. The type ``void`` means the function does not return anything. You can
  159. use any type, as with variables:
  160. ::
  161. func hit(damage: float) -> bool:
  162. health_points -= damage
  163. return health_points <= 0
  164. You can also use your own nodes as return types:
  165. ::
  166. # Inventory.gd
  167. # Adds an item to the inventory and returns it.
  168. func add(reference: Item, amount: int) -> Item:
  169. var item: Item = find_item(reference)
  170. if not item:
  171. item = ItemDatabase.get_instance(reference)
  172. item.amount += amount
  173. return item
  174. Typed or dynamic: stick to one style
  175. ------------------------------------
  176. Typed GDScript and dynamic GDScript can coexist in the same project. But
  177. I recommended to stick to either style for consistency in your codebase,
  178. and for your peers. It’s easier for everyone to work together if you
  179. follow the same guidelines, and faster to read and understand other
  180. people’s code.
  181. Typed code takes a little more writing, but you get the benefits we
  182. discussed above. Here’s an example of the same, empty script, in a
  183. dynamic style:
  184. ::
  185. extends Node
  186. func _ready():
  187. pass
  188. func _process(delta):
  189. pass
  190. And with static typing:
  191. ::
  192. extends Node
  193. func _ready() -> void:
  194. pass
  195. func _process(delta: float) -> void:
  196. pass
  197. As you can see, you can also use types with the engine’s virtual
  198. methods. Signal callbacks, like any methods, can also use types. Here’s
  199. a ``body_entered`` signal in a dynamic style:
  200. ::
  201. func _on_Area2D_body_entered(body):
  202. pass
  203. And the same callback, with type hints:
  204. ::
  205. func _on_area_entered(area: CollisionObject2D) -> void:
  206. pass
  207. You’re free to replace, e.g. the ``PhysicsBody2D``, with your own type,
  208. to cast parameters automatically:
  209. ::
  210. func _on_area_entered(bullet: Bullet) -> void:
  211. if not bullet:
  212. return
  213. take_damage(bullet.damage)
  214. The ``bullet`` variable could hold any ``CollisionObject2D`` here, but
  215. we make sure it is our ``Bullet``, a node we created for our project. If
  216. it’s anything else, like an ``Area2D``, or any node that doesn’t extend
  217. ``Bullet``, the ``bullet`` variable will be ``null``.
  218. Warning system
  219. --------------
  220. The warning system complements typed GDScript. It’s here to help you
  221. avoid mistakes that are hard to spot during development, and that may
  222. lead to runtime errors.
  223. You can configure warnings in the Project Settings under a new section
  224. called ``GDScript``:
  225. .. figure:: ./img/typed_gdscript_warning_system_settings.png
  226. :alt: warning system project settings
  227. warning system project settings
  228. You can find a list of warnings for the active GDScript file in the
  229. script editor’s status bar. The example below has 3 warnings:
  230. .. figure:: ./img/typed_gdscript_warning_example.png
  231. :alt: warning system example
  232. warning system example
  233. To ignore specific warnings in one file, insert a special comment of the
  234. form ``#warning-ignore:warning-id``, or click on the ignore link to the
  235. right of the warning’s description. Godot will add a comment above the
  236. corresponding line and the code won’t trigger the corresponding warning
  237. anymore:
  238. .. figure:: ./img/typed_gdscript_warning_system_ignore.png
  239. :alt: warning system ignore example
  240. warning system ignore example
  241. Warnings won’t prevent the game from running, but you can turn them into
  242. errors if you’d like. This way your game won’t compile unless you fix
  243. all warnings. Head to the ``GDScript`` section of the Project Settings to
  244. turn on this option. Here’s the same file as the previous example with
  245. warnings as errors turned on:
  246. .. figure:: ./img/typed_gdscript_warning_system_errors.png
  247. :alt: warnings as errors
  248. warnings as errors
  249. Cases where you can’t specify types
  250. -----------------------------------
  251. To wrap up this introduction, let’s cover a few cases where you can’t
  252. use type hints. All the examples below **will trigger errors**.
  253. You can’t use Enums as types:
  254. ::
  255. enum MoveDirection {UP, DOWN, LEFT, RIGHT}
  256. var current_direction: MoveDirection
  257. You can’t specify the type of individual members in an array. This will
  258. give you an error:
  259. ::
  260. var enemies: Array = [$Goblin: Enemy, $Zombie: Enemy]
  261. You can’t force the assignment of types in a ``for`` loop, as each
  262. element the ``for`` keyword loops over already has a different type. So you
  263. **cannot** write:
  264. ::
  265. var names = ['John', 'Marta', 'Samantha', 'Jimmy']
  266. for name: String in names:
  267. pass
  268. Two scripts can’t depend on each other in a cyclic fashion:
  269. ::
  270. # Player.gd
  271. extends Area2D
  272. class_name Player
  273. var rifle: Rifle
  274. ::
  275. # Rifle.gd
  276. extends Area2D
  277. class_name Rifle
  278. var player: Player
  279. Summary
  280. -------
  281. Typed GDScript is a powerful tool. Available as of version 3.1 of Godot, it
  282. helps you write more structured code, avoid common errors, and
  283. create scalable systems. In the future, static types will also bring you
  284. a nice performance boost thanks to upcoming compiler optimizations.