In a library, if you wanted a book, you could look through all the books until you find the one you want. But generally, you'll go through an index of all the books and find the one you want.
In programming, indirection is where instead of directly accessing a particular piece of data or resource, you access it indirectly through an intermediate step.
Anytime you need to jump from one location to another in your files, it's an added "level of indirection".
Here's code with some indirection. This is a button that sorts items by their value in a hypothetical inventory. The item's value is halved if the items has been used a lot.
@onready var button := $Button
func _ready() -> void:
button.pressed.connect(_on_button_pressed)
func get_item_value(item: Item) -> int:
if item.usage > 0.5:
return item.value / 2.0
else:
return item.value
func _compare_items(a: Item, b: Item) -> bool:
return get_item_value(a) < get_item_value(b)
func _on_sort_button_pressed() -> void:
inventory_items.sort_custom(
_compare_items
)
A lot of real code has much more indirection than that, spread accross multiple files.
Here is the same functionality, without indirection, using lambdas:
@onready var button := $Button
func _ready() -> void:
button.pressed.connect(
func() -> void:
inventory_items.sort_custom(
func(a: Item, b: Item) -> bool:
var value_a := item.value / 2.0 if item.usage > 0.5 else item.value
var value_b := item.value / 2.0 if item.usage > 0.5 else item.value
return value_a < value_b
)
)
A lot of programming advice recommends to enclose everything in functions, and to have a lot of indirection.
I don't think it's often the best advice. Yes, in the code above, there is some repetition of the same code twice.
But on the other hand, the code is self-contained, its usage clearer, and we can read it like a book, instead of jumping around. If we needed to change something, for example calculate the value differently for value_b
, we could do so instantly.
Code with fewer indirection has a few key benefits:
- it often requires less naming: we can use lambdas, or expressions
- it often requires less documentation: we can see how its used from context
- it is safer to change: you can change a few lines inside a function and confidently know you can't break anything, whereas changing an isolated piece of code is less certain.
- it is easier to delete: Deleting lines is easy, but deleting an isolated piece of code is dangerous: what if something else was using it?
For that reason, at GDQuest we tend to consider indirection as an extra level of abstraction, that we only use when it really helps, after having given it due consideration.See Also
Related terms in the Glossary