How does yielding to the completed signal conditionally work?

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

I am reading the docs, specifically GDScript basics and there is this section about coroutines I am struggling to understand:

If you’re unsure whether a function may yield or not, or whether it may yield multiple times, you can yield to the completed signal conditionally:

I was having a tough time understanding the code so I ran it in godot to see what happened. Because of the pseduorandom nature I modified the code slightly (but I don’t think it changes the example). Here is my code I used:

extends Node

func generate():
	var result = rand_range(-1.0, 1.0)

	if result < 0.0:
		yield(get_tree(), "idle_frame")

	return result


func make():
	var result = generate()

	if result is GDScriptFunctionState: # Still working.
		result = yield(result, "completed")

	return result


func _ready():
	randomize()
	print(make())

Here’s what I am struggling to understand:

It’s my understanding that this code is supposed to always return a random number (above 0?). But sometimes I get a random number, sometimes I get a function state.

With this example, I’m not sure how yielding to the completed signal conditionally works.

This is particularly difficult, because I’m not even sure what this part of the documentation is trying to teach.

Sorry for the bad question, but thanks for reading and I hope you can help.

:bust_in_silhouette: Reply From: AlexTheRegent

yield is shorthand for connect method. yield does not make your code asynchronous and does not stop execution of your function until it is resolved.
Your code will be executed as next code:

extends Node

func generate():
    var result = rand_range(-1.0, 1.0)

    if result < 0.0:
        connect("idle_frame", get_tree(), "generate")
		return GDScriptFunctionState
	else:
		return result


func make():
    var result = generate()

    if result is GDScriptFunctionState: # Still working.
		connect("completed", self, "_on_completed")
	
	return result
		
func _on_completed():
	pass


func _ready():
    randomize()
    print(make())

Hopefully you will understand why you misunderstand yield usage. If not, here’s example of how your code can be modified to work as expected:

extends Node

func generate(callback):
    var result = rand_range(-1.0, 1.0)

	while result < 0.0:
        yield(get_tree(), "idle_frame")
		result = rand_range(-1.0, 1.0)

    call(callback, result)


func make():
    var result = generate("_on_generated")


func _on_generated(result):
    print(result)


func _ready():
    randomize()
    make()

Unfortunately, you can’t print result in _ready() function, because yield does not return values from coroutines.

Thank you for this explanation. yield being shorthand for connect (and the separate return GDScriptFunctionState) is very enlightening.

newbie2356 | 2021-11-16 00:20

This is an excelent explanation. Thank you!

f.avari | 2022-04-07 00:24