awaitable functions

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Imma

Is this the best way to make a function awaitable?

func async_function() -> Signal:
    await some_other_function()
    return get_tree().create_timer(0).timeout

It feels like there has to be a better way

1 Like
:bust_in_silhouette: Reply From: Gluon

Try using yield, create a test program and try the following

var exam = yieldtest()
var Ti

func _ready():
    exam
    timer("_yieldrun")

func yieldtest():
    print("yieldtest 1")
    yield()
    print("yieldtest 2")

func _yieldrun():
    print("Yieldrun Print")
    exam.resume()

func timer(yiel):
    print("timertest")
    Ti = Timer.new()
    Ti.autostart = true
    Ti.one_shot = true
    Ti.wait_time = 2
    Ti.connect("timeout", self, yiel)
    add_child(Ti)

This will give you a good idea of how yield works. Bear in mind that process functions will continue while yield is held though.

Documentation on yield is found here,

The asker of the question is using Godot 4.0; yield no longer exists in that version.

SQBX | 2023-01-02 03:53

:bust_in_silhouette: Reply From: SQBX

The await keyword can be used to create coroutines that wait until a signal is emitted before continuing execution. Using the await keyword with a signal or a call to a function that is also a coroutine will immediately return the control to the caller. When the signal is emitted (or the called coroutine finishes), it will resume execution from the point where it stopped.

For example, to stop execution until the user presses a button, you can do something like this:

func wait_confirmation():
    print("Prompting user")
    await $Button.button_up # Waits for the button_up signal from Button node.
    print("User confirmed")
    return true

In this case, the wait_confirmation becomes a coroutine, which means that the caller also needs to await for it:

func request_confirmation():
    print("Will ask the user")
    var confirmed = await wait_confirmation()
    if confirmed:
        print("User confirmed")
    else:
        print("User cancelled")

Note that requesting a coroutine’s return value without awaiting will trigger an error:

func wrong():
    var confirmed = wait_confirmation() # Will give an error.

However, if you don’t depend on the result, you can just call it asynchronously, which won’t stop execution and won’t make the current function a coroutine:

func okay():
    wait_confirmation()
    print("This will be printed immediately, before the user press the button.")

If you use await with an expression that isn’t a signal nor a coroutine, the value will be returned immediately and the function won’t give the control back to the caller:

func no_wait():
    var x = await get_five()
    print("This doesn't make this function a coroutine.")

func get_five():
    return 5

This also means that returning a signal from a function that isn’t a coroutine will make the caller await that signal:

func get_signal():
    return $Button.button_up

func wait_button():
    await get_signal()
    print("Button was pressed")