See all glossary terms

Setters and Getters

Setters and getters are functions associated with variables. They allow you to run code when you assign a value to a variable (setter) or when you read its value (getter). They are also tools to filter and validate data coming in or out of variables.
In GDScript, there are two ways to define setters and getters. The first one is to write them directly under a script-wide variable:
Here's one example:
var health := 10:
    set(new_health):
        health = max(0, new_health)
    get:
        return health
The line set(new_health): defines a setter function, and get: defines a getter function. It's a short syntax designed to define setters and getters directly under the variable.
In your script, when you write something like health = -5, the setter function will run and assign 0 to the health variable (because the new health value is lower than 0 and the setter function filters that). When you write print(health), the getter function will run and return the current value of health variable.
The second way to define setters and getters is to use the set and get keywords and point to a specific function. Here's the same example as above, but using the set and get keywords. You can define the associated setter and getter functions anywhere in the script:
var health := 10: set = set_health, get = get_health

func set_health(new_health: int) -> void:
    health = max(0, new_health)

func get_health() -> int:
    return health
Which syntax is better?
As with many things in code, neither syntax is really better. It's a matter of taste and what you find more readable.
The first syntax keeps the setter and getter functions close to the variable, and you can fold the code in the editor to hide them. The second syntax keeps the variable declaration concise, and the setter and getter functions can be placed anywhere in the script. This is the one we favor in our courses.
With code style, I recommend sticking to one syntax in your project for consistency. Consistency makes the code easier for you and your teammates to read and understand.

When to use setters

You may use a setter function to filter unwanted values. In this example, nothing will happen if you try to set age to 0, a negative value, or a value higher than 100.
var age := 15: set = set_age

func set_age(new_age: int) -> void:
    if new_age > 0 and new_age < 100:
        age = new_age
Setters are also useful for triggering events. For example, you may want to save a value to a file every time it changes:
var current_profile_name := "Player 1":
    set(new_profile_name)
        current_profile_name = new_profile_name
        save()

Why would I use getters?

A little disclaimer first: we rarely use getter at GDQuest. But here are examples of how you could use getters.
Getters can be useful when calculating a value based on other values. For example, you may want to convert a temperature from Celsius to Fahrenheit:
var celsius := 37
var farenheit: float: get = get_farenheit

func get_farenheit() -> float:
    return (celsius * 9/5) + 32.0
With this code, when you write print(farenheit), the formula will always apply and give you the correct value, even if you change the celsius variable.
You may also use getters to load something only on demand. For example, you may want to load high scores from a file only when needed. In this case, you may use a getter to load the high scores.
var high_scores: Resource = null: get = get_high_scores

func get_high_scores() -> Resource:
    return load("user://high_scores.tres")

func display_scores() -> void:
    for score in high_scores.scores:
        var score_node := Label.new()
        score_node.text = score
        $ScoresList.add_child(score_node)
Finally, you may use a getter to make a read-only property:
var account_authentication_key = "": set = set_account_authentication_key, get = get_account_authentication_key

func set_account_authentication_key(new_key: String) -> void:
    push_error("you cannot change this property")

func get_account_authentication_key() -> String:
    return load("user://auth.tres").key

Setters and Getters together

Setters are more often used than getters, but there are cases where you want to use both, for example, when you want to keep two properties in sync.
Here are two properties representing time in seconds and milliseconds. You can set the time in seconds, and it will automatically update the milliseconds value. You can also get the time in seconds, and it will return the correct value from the milliseconds value.
var milliseconds := 0.0
var seconds: float: get = get_seconds, set = set_seconds

func get_seconds() -> float:
    return milliseconds / 1000

func set_seconds(new_seconds: float) -> void:
    milliseconds = new_seconds * 1000
Can't I use plain functions instead?
Yes! That's a good observation. Indeed, you could use functions for all the above instead of variables with setters and getters. Setters and getters kind of hide how a variable works. This is a conscious choice in some programming styles, where we try to hide the inner workings of code. Other developers may prefer to be more explicit and expose how all the code works.
I prefer code to be explicit, so I'm not fond of setters and getters. I like to see the code that runs when I assign a value to a variable. Still, setters and getters do have some benefits:
  • Refactoring: If you already have a property used in a codebase and you now want to change its behavior, adding a setter to it does that without changing the code that uses the property. This is a good way to refactor code without breaking it.
  • Standardization: using setters and getters limits you. You can only use one parameter for setters and zero for getters (as opposed to functions, which are more flexible). Setters have to use the type of your variable. Constraints like these force you to write code that meets some expectations.
  • Consistency: if setters and getters are already used in a codebase, it's always good to stick to the same style. Consistency makes the code easier for everyone involved to read and understand. It's less cognitive load compared to having to process different styles.
Consistency is largely why you'll find setters and getters in GDQuest code: Godot already uses them, and lots of people in the community do, so we do too, to make our code more accessible to others.

See Also

Related terms in the Glossary