See all glossary terms

Footgun

When you point a loaded gun at your feet, you risk shooting yourself.
In programming, any piece of code may have unintended consequences; but some patterns are considered "footguns": when the code is written in such a manner that it makes unintended behavior easy, that's a footgun.
This term is usually applied to language design decisions that affect all users of the language. All languages contain some footguns that trip even experienced programmers, because they differ from previous footguns they were used to in another language.
But you can also apply the term to your own code, that will trip your co-workers or yourself in the future.
Generally, all APIs will contain some footguns, because it is not possible to make everything explicit using text. This is one of the limitations of text-based programming.

An example of a footgun

Here's a very basic example. Say you're making a calculator that adds two numbers. People type their numbers in a text field, and you receive text. You want to add the texts together.
@onready var line_edit_1 := $LineEdit
@onready var line_edit_2 := $LineEdit2

func add() -> void:
	var number_1 := line_edit_1.text()
	var number_2 := line_edit_1.text()
	var result := number_1 + number_2
	print(result)
In this example, if the user entered 1 and 1, the result would be 11 instead of 2. Did you spot it?
We never transformed the text into a number. Instead, we just added the two texts together.
For any experienced programmer, that isn't much of a footgun, because it's expected behavior. But for beginners, it could be very tricky. How could we avoid this footgun? By making the implicit behavior explicit.
For example, some languages refuse to use the same operators for different types. You wouldn't be able to use + in PHP for example. To concatenate strings, PHP uses .. You would need to write string_1 . string_2 (but then PHP allows + to append arrays...).

How to avoid footguns

  • Use types everywhere.
  • Avoid implicit coercion.
  • Avoid side effects.
  • Avoid unecessary options and branches; we tend to always think "what if..." and try to cater for that; it's often far better to restrict options and be strict.
  • Name everything as clearly as possible.
  • Document everything, specially everything that cannot be captured in code. For example, there's an int type, but if negative numbers are illegal, the type cannot capture that.
In general, avoid any implicit or magic behavior.

See Also

Related terms in the Glossary