Function Call vs Function Reference

Function references can be tricky.

Syntax

What's the difference between:

func _ready() -> void:
  launch_rockets()

func launch_rockets() -> void:
  print("Launching rockets!")

And:

func _ready() -> void:
  launch_rockets

func launch_rockets() -> void:
  print("Launching rockets!")

In the first example, launch_rockets() is called, and the function executes. In the second example, launch_rockets refers to the function, and it's not called. It's just the function's name.

Remember, a function is like a recipe in a cooking book. For example, if the book has a recipe for a chocolate cake, I could tell you to "make the cake". That's like calling the function. But if I say "chocolate cake", that's like just giving you the recipe's name.

The () at the end of a function name is a shortcut for "call this function". It is actually a shortcut for .call(). launch_rockets() is the same as launch_rockets.call().

Functions can be substituted for their results

Do you remember how you used to reduce a math equation?

y = (2 + 3) * (5 * (1+1))
y = 5 * (5 * 2)
y = 5 * 10
y = 50

You first resolve internal parentheses. Programming languages do the same with functions.

In the example below, five() and three() are functions that return numbers. When you call them, you get the number they return. They get evaluated by Godot before print() is called:

func five() -> int:
  return 5

func three() -> int:
  return 3

func _ready() -> void:
  print(five() + three())

Note that print(five + three) wouldn't work, as you can't add function references together.

Use cases

Where do you use function references? One everyday use is in connect().

When connecting a signal to a function, you reference the function's name. For example:

tween.finished.connect(launch_rockets)

This tells the tween to call launch_rockets when it's finished. Using the cake example again, it'd be like saying, "When the tween finishes, make the recipe called chocolate cake".

In contrast, if you use parentheses, you're calling the function, and that's probably not what you want:

tween.finished.connect(launch_rockets())

Because launch_rockets() finishes first and returns void, the expression becomes:

tween.finished.connect(null)

In plain language, that'd be like saying: "Make the cake. When the tween finishes, cake", which doesn't make sense since "cake" is not an action.

The problem of arguments

Sometimes, you want to use a function reference, but you want to give it arguments.

For example, the Button's pressed signal doesn't give you any arguments. But what if you want to pass the button's name to the function?

One way is to use lambda functions. They're like mini-functions that you can define on the spot. For example:

button.pressed.connect(func() -> void:
  launch_rockets(button.name)
)

Another is to use the bind() function. bind creates a new function that calls the original function with the arguments you provided:

button.pressed.connect(launch_rockets.bind(button.name))

In this case, bind creates a new function that calls launch_rockets with the button.name argument. It's similar to using the lambda function, but it's more concise.

Become an Indie Gamedev with GDQuest!

Don't stop here. Step-by-step tutorials are fun but they only take you so far.

Try one of our proven study programs to become an independent Gamedev truly capable of realizing the games you’ve always wanted to make.

Nathan

Founder and teacher at GDQuest
  • Starter Kit
  • Learn Gamedev from Zero
Check out GDSchool

You're welcome in our little community

Get help from peers and pros on GDQuest's Discord server!

20,000 membersJoin Server

Contribute to GDQuest's Free Library

There are multiple ways you can join our effort to create free and open source gamedev resources that are accessible to everyone!