Godot: Implement return value from yield()

Created on 19 Feb 2015  ·  3Comments  ·  Source: godotengine/godot

To create generator functions, we need yield(value) to be implemented. This would act like yield(), but 'value' would be passed back and returned from the resume() call.

This would allow range() to be made into an iterator, rather than creating a potentially huge array.

This would also be a step towards nice features like list/dict comprehension.

archived feature proposal gdscript

Most helpful comment

I've just started working with Godot (liking it so far) but I agree that it feels that yield() should be able to return more than the function state. Yield is like returning with the ability to resume() so the function should be able to "return" a value by yielding.

One possible approach I have been thinking of is augmenting [GDScript]FunctionState
( https://docs.godotengine.org/en/3.1/classes/class_gdscriptfunctionstate.html )
to have a method value() which returns the argument to yield().

func co1():
     yield(5)

s = co1()
print(s.value())   # prints 5

GDscript already has a yield which takes two values and waits on a signal. However, this one argument version would just return its argument in the FunctionState. With just that change a generator could be written like:

func xrange(count):
    var i = 0
    while i < count:
        yield(i)

func do_stuff():
    var it = xrange(5)
    while it:
        print(it.result())
        it = it.resume()

This works quite nicely but there is a subtlety worth considering. When the coroutine function returns (instead of yielding) a value is returned not a FunctionState. In the above example null is returned (because the function is void) which we test to stop the loop in do_stuff(). If the coroutine function returns a value [eg. imagine return false at the end of xrange()] then that test would break.

I think I'll take a look at the code.
IMO, yield(value) would be, erm, valuable.

EDIT: Looking at the code there are complications with the signal version of yield so the section that I'd written below about it is removed for now. May elaborate later.

All 3 comments

Unpleasant workaround:

func xrange(count, dict):
    var i = 0
    while i < count:
        dict.next = i
        yield()
        i += 1

func do_stuff():
    var curr = {}
    var it = xrange(5, curr)
    while curr.value != null:
        print(curr.value)
        it.resume()

I've just started working with Godot (liking it so far) but I agree that it feels that yield() should be able to return more than the function state. Yield is like returning with the ability to resume() so the function should be able to "return" a value by yielding.

One possible approach I have been thinking of is augmenting [GDScript]FunctionState
( https://docs.godotengine.org/en/3.1/classes/class_gdscriptfunctionstate.html )
to have a method value() which returns the argument to yield().

func co1():
     yield(5)

s = co1()
print(s.value())   # prints 5

GDscript already has a yield which takes two values and waits on a signal. However, this one argument version would just return its argument in the FunctionState. With just that change a generator could be written like:

func xrange(count):
    var i = 0
    while i < count:
        yield(i)

func do_stuff():
    var it = xrange(5)
    while it:
        print(it.result())
        it = it.resume()

This works quite nicely but there is a subtlety worth considering. When the coroutine function returns (instead of yielding) a value is returned not a FunctionState. In the above example null is returned (because the function is void) which we test to stop the loop in do_stuff(). If the coroutine function returns a value [eg. imagine return false at the end of xrange()] then that test would break.

I think I'll take a look at the code.
IMO, yield(value) would be, erm, valuable.

EDIT: Looking at the code there are complications with the signal version of yield so the section that I'd written below about it is removed for now. May elaborate later.

There's some problems on how yield works, so it'll replaced by await which is more straight-forward. I'm not sure yet whether we'll do actual generators.

If you are still interested in the idea of adding generators, please open a new proposal on the GIP tracker following the given issue template (after checking that it doesn't exist already). You can reference this issue and summarize the ideas in the proposal. Thanks in advance!

Was this page helpful?
0 / 5 - 0 ratings