How to Enforce Static Typing in GDScript

This post is written for programmers who have experience working with statically typed languages and want a similar experience when working with GDScript. It supplements the official Godot docs page on Static typing in GDScript.

Index

Project and Editor Settings

Godot 4.2 introduces a valuable way to disable dynamic typing features in GDScript by enforcing static typing: The editor can throw a warning or error whenever untyped declarations are found in your scripts. This is in addition to existing warning options relating to unsafe code.

Here is a configuration that modifies GDScript to behave more like a statically typed language:

Project Settings (Advanced Settings)

Debug → GDScript:

  • Untyped Declaration: Error
  • Unsafe Property Access: Error
  • Unsafe Method Access: Error
  • Unsafe Cast: Warn
  • Unsafe Call Argument: Error

Editor Settings

  • Text Editor → Completion → Add Type Hints: On

Why Disable Dynamic Typing Features?

Even without using these project and editor settings, GDScript supports both dynamic and static typing. The Godot script editor even has a safe lines feature to visualize which lines of code use static typing and which use dynamic. So why disable these dynamic typing features altogether?

Prevent Accidental Dynamic Typing

The first reason is pretty obvious: you may intend to write statically typed code, but accidentally write dynamically typed code instead. The safe lines feature may alert you to this, but maybe you didn’t notice the line number wasn’t the colour you wanted it to be. This may lead to writing a function call that you believe will be safe, only to discover at runtime that you were calling a function that doesn’t exist on a type that you did not intend to use. These runtime errors can be prevented by turning them into compile time script errors with static typing.

You’re Used to Working With Statically Typed Languages

When you have worked with statically typed languages for a long time, you may expect your compiler to help you avoid certain types of errors in your code. After switching to a dynamically typed language, you may find yourself accidentally writing runtime errors solely because you expected the compiler to prevent them.

This is especially relevant to game developers who have worked with C# with the Unity game engine. In fact, I would guess that one of the reasons that some game developers with experience in C# want to continue using C# in Godot instead of GDScript is because they want static typing features enforced in their programming language. By enforcing static typing in GDScript, it can make the language more accessible to those who are used to working with statically typed languages.

Enforce Consistent Code Style

As described in the Godot documentation, it can be better for a project to stick to one code style. Disabling dynamic typing features helps you enforce a certain code style for your entire code base.

Guarantee Other Benefits of Static Typing

There are a number of benefits to using static typing in your scripts, but without the compiler forcing you to use static typing, it can be easy to unintentionally use bits of dynamic code here and there throughout your project. Some of the benefits that static typing provides that have not been mentioned yet are:

Tips and Caveats

Script Errors Do Not Block Export

Many developers who are used to working with pre-compiled languages may be caught off guard by this one: None of the script errors detected by the Godot editor will block you from exporting your project with those scripts. Additionally, the type of errors discussed in this post, such as untyped declaration errors, will not trigger in an exported build: they are specific to the script editor and debugging through the Godot editor.

To ensure that no script errors exist in exported project, you can review the console output when loading your project in the editor.

For a continuous integration build system, monitor for SCRIPT ERROR logs when exporting your project. If any are found, simply discard the export and mark it as failed:

godot.windows.editor.x86_64.console.exe --headless --export-release "Windows Desktop" path/game.exe

Alternatively, you can monitor for SCRIPT ERROR logs before exporting by running one iteration of your game:

godot.windows.editor.x86_64.console.exe --headless --quit

More information on the command interface for Godot can be found in the docs.

Use Typed Arrays

Typed Arrays can allow runtime errors to be caught at compile time instead of runtime. Here is an example of using a typed Array to catch an invalid assignment error at compile time:

var typed_array: Array[int] = [1, 2, 3]
var compile_error: Node3D = typed_array[0]

Conversely, using an untyped Array to do the same thing would result in a runtime error rather than a compile error:

var untyped_array: Array = [1, 2, 3]
var runtime_error_1: Node3D = untyped_array[0]
var implicit_untyped_array := [1, 2, 3]
var runtime_error_2: Node3D = implicit_untyped_array[0]

Unsafe Assignments and Casts

Some unsafe assignments and casts are necessary in GDScript. For example, a Dictionary can have keys or values with different types. Even if all keys or values are the same type in the Dictionary, an unsafe assignment or cast will be required to access these. This is because, in the backend, a Dictionary uses the Variant type to store keys and values.

Although a warning can be produced for unsafe casts using the “Unsafe Cast” project setting, there is no option to produce a warning or error when an unsafe assignment is used; for this, you can only rely on the safe lines feature of the built-in script editor. But with the project settings suggested in this post, I believe it is rare, if ever, that you will be able to make an unsafe assignment that could have been written as a safe assignment without unsafe casts. Here are some code snippets to help you understand unsafe and safe assignments:

Unsafe assignment: This example gives no script warning/error. Instead, the second line will trigger a runtime error: Trying to assign int to Vector2.

var dict: Dictionary = { "my_key": 42 }
var vec2_var: Vector2 = dict["my_key"]

Safe assignment: This example will give a narrowing_conversion warning in the script editor for the second line because the float is being converted to an int for this assignment, which is a safe assignment.

var float_var: float = 2.1
var int_var: int = float_var

Script compile error: The second line of this example will trigger a script compilation error: Cannot assign String to int.

var string_var: String = "A string of text"
var int_var: int = string_var

Disabling Script Errors in Certain Files

By default, Godot will ignore warnings in the res://addons folder. You can find this setting under Project Settings (Advanced Settings) → Debug → GDScript → Exclude Addons.

For specific lines, use the @warning_ignore just before the line you want to ignore. This also applies to warnings that are configured as script errors. For example:

@warning_ignore("untyped_declaration")

More details can be found on the GDScript warning system docs page.

Further Reading

The Godot documentation has a great write-up on Static typing in GDScript. It’s a must read for anyone looking to use static typing features.

Feedback

Godot and GDScript are always evolving. If you think anything in this post could be improved or updated, don’t hesitate to let me know!


Posted

in

by

Tags: