My inclination when working with a programming language is to do things in a very type-safe way and as a result, I’m used to architectural patterns which take advantage of type safety to make things easier to write and maintain.
gdscript
, however, is not a language which has a strong type system. So, the same patterns I love in type-safe languages end up causing me grief as I try to apply them.
What I’ve been looking for are new patterns which work well within the world of gdscript
and there’s one specific example that I’m untangling right now that can be used as an example.
Imagine you have a packed scene which contains a UI element that represents some setting in your save state that you can modify with a top level script, like this:
The problem arises when you might have multiple settings that represent different kind of sensitivities. One solution is to make a new packed scene for each setting, copy-paste the original code into a new class for that scene, and modify how the data gets saved.
This sucks because you have a bunch of classes and packed scenes that are almost identical, increasing the maintenance cost when you want to change something across all of them.
So you might say “okay, lets just choose how we save the data with an enum”, like this:
But because Godot doesn’t have case analysis, it can’t guarantee that all possible execution paths have been addressed as you end up needing an assertion for each match block to potentially catch the issue at runtime.
As it turns out, and perhaps this is obvious to other Godot developers, I’ve found that relying on signals is a better way to solve this problem in Godot:
Then, you connect value_changed
to some other place where you actually save the data to your save state. This solution avoids Godot’s lack of complete case analysis
as well as the boilerplate problem from having bunch of what are essentially the same class/scene duplicated many times for each setting.
It also decouples the responsibility of what to do with the value from the UI element. Otherwise, we would need to continually update the SensitivitySetting
class to handle our new cases.
Obviously, in retrospect, this is more or less the design patten used for built-in Godot Control
nodes, and it interoperates well with other Control
nodes.