Calling a function with yield within a yield called function makes strange behaviour

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

Hi there,
this code:

func _ready():
    print("Staring game")
    yield(Chapter1(), "completed")
    print("All Done.")

func printMsg(text1)    :
    yield(get_tree(), "idle_frame")
    print("### 1 ### " + "Durchlauf: " + text1)
    printAText("!!! 2 !!!")
    #yield(printAText("### 2 ###"), "completed")
    yield(get_tree().create_timer(1), "timeout")
    print("### 3 ###")
    printAText("!!! 4 !!!")
    #yield(printAText("### 4 ###"), "completed")
    yield(get_tree().create_timer(1), "timeout")
    print("### 5 ###")
    
func printAText(text):
    yield(get_tree().create_timer(3), "timeout")
    print(text)
    yield(get_tree().create_timer(3), "timeout")
    
func Chapter1():
    yield(get_tree(), "idle_frame")
    print("Entering Chapter1")
    yield(printMsg("Eins"), "completed")
    yield(printMsg("Zwei"), "completed")
    print("Exiting Chapter1")

results in an unexpected execution order. The output is:
Staring game
Entering Chapter1

1 ### Durchlauf: Eins

3

5

1 ### Durchlauf: Zwei

3

!!! 2 !!!
!!! 4 !!!

5

Exiting Chapter1
All Done.
!!! 2 !!!
!!! 4 !!!

But I expected:
Staring game
Entering Chapter1

1 ### Durchlauf: Eins

2

3

4

5

1 ### Durchlauf: Zwei

2

3

4

5

Exiting Chapter1
All Done.

What am I doing wrong?

:bust_in_silhouette: Reply From: Inces

Interesting. Looks like the loop ignored yielding for #2 and #4. At that point your function went separately from non-yield calls of !2 and !4. Could it be, that forcing yielding function to run consecutively is the problem ? Try to erase lines of non-yield prints !2 and !4.

You should also finish all yield functions with RETURN keyword.
Maybe the reason is tree timer, it generally is buggy. You could try to swap it with Timer node. Finally, You can debug by yielding for custom signals, instead of “completed”

:bust_in_silhouette: Reply From: jaguar1983

This is actually working exactly as it’s supposed to. When you call a coroutine (any function containing a yield), it runs up to the first yield and then returns to the calling function a GDScriptFunctionState that describes the state of that coroutine.

It does not pause the calling function until it is finished, it returns to the caller which then continues. You’ve actually commented out the correct line yield(printAText("### 4 ###"), "completed") which would do what you expect it to.