Proposal: Add generator functions to the language


(Taras Zakharko) #1

Personally, I am agains generators (its quite specific syntactic sugar that adds a lot of complexity), but I would be all for a comprehensive coroutine library*. One can model it after Lua’s coroutines (http://www.lua.org/pil/9.1.html), which works well with the existing syntax. Your example becomes something like:

helloGenerator = Coroutine.create<()->String>({name:String -> () in
   Coroutine.yield(“Hello”)
   Coroutine.yield(name ?? “World”)
})

this generates a class instance with a resume ()->String? method that can be used to retrieve the values. You can also pass values via resume (they will be then available as results of coroutine.yield)

One can than use helloGenerator.resume() to get the values (which can be easily wrapped in a sequence etc).

Benefits of this approach: no need for significant syntactic change (although a coroutine keyword could be introduced instead of func to wrap the above declaration), the coroutine functions are offloaded to a type rather than syntactic construct, type safety is quite easy to preserve. Still, its far from being a trivial thing to implement as it would require support of continuations on the compiler level.

Cheers,

Taras

*Yes, current generators in Python are essentially coroutines but I think it important to keep the terminology clean. Generators are intended first and foremost as lazy sequence, well, generators. Coroutines are a much more versatile construct.

···

On Fri, Dec 11, 2015 at 18:21 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Looking for feedback on crafting a proposal adding generator functions to Swift. I understand this will likely be a very involved proposal at the language level, although I actually don’t know the complexity of the change within the Swift compiler itself.


(David Waite) #2

Because stackful coroutines quickly start to quickly approximate threading, I didn’t think they were appropriate to propose at this time. That said:

I think you would probably want something like Coroutine.create<String,()> so that the String->() and ()->String interfaces of the two objects can be generated. Likewise, in your example I believe a Coroutine-related protocol instance should be passed in that exposes a yield(value:String) -> () method

Coroutines and generator functions both involve additional rules for cleanup. Imagine a coroutine or generator which walks a file or network stream, returning individual lines of text. The code using .resume() may stop reading once they recognize the line they need or encounter an error, but the system still needs to be able to reclaim the coroutine as well as close/reclaim the local/network stream resources.

The references need to be set up in such a way that objects are reclaimed in a predictable order, and defer blocks would probably be supported and run, to make such control flow more obvious. This compiler support which would be required whether you were doing (sequence) generator functions or “full” coroutines. In the generator case, such cleanup needs to be moved to the teardown of your state objects. It is possible some of the cleanup for full coroutines would be shared with pre-existing thread termination support.

Finally - any calls to yield might never resume, and it is possible your code will transition between processors/parent threads on the subsequent resume. This pushes me toward promoting a keyword vs using Coroutine.yield, and restricting use of the yield keyword to make such behavior more obvious (in the same way throws must be declared and try must be used when calling an error-throwing method today)

-DW

···

On Dec 12, 2015, at 9:43 PM, Taras Zakharko via swift-evolution <swift-evolution@swift.org> wrote:

Personally, I am agains generators (its quite specific syntactic sugar that adds a lot of complexity), but I would be all for a comprehensive coroutine library*. One can model it after Lua’s coroutines (http://www.lua.org/pil/9.1.html), which works well with the existing syntax. Your example becomes something like:

helloGenerator = Coroutine.create<()->String>({name:String -> () in
   Coroutine.yield(“Hello”)
   Coroutine.yield(name ?? “World”)
})

this generates a class instance with a resume ()->String? method that can be used to retrieve the values. You can also pass values via resume (they will be then available as results of coroutine.yield)

One can than use helloGenerator.resume() to get the values (which can be easily wrapped in a sequence etc).

Benefits of this approach: no need for significant syntactic change (although a coroutine keyword could be introduced instead of func to wrap the above declaration), the coroutine functions are offloaded to a type rather than syntactic construct, type safety is quite easy to preserve. Still, its far from being a trivial thing to implement as it would require support of continuations on the compiler level.

Cheers,

Taras

*Yes, current generators in Python are essentially coroutines but I think it important to keep the terminology clean. Generators are intended first and foremost as lazy sequence, well, generators. Coroutines are a much more versatile construct.

On Fri, Dec 11, 2015 at 18:21 PM, David Waite via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Looking for feedback on crafting a proposal adding generator functions to Swift. I understand this will likely be a very involved proposal at the language level, although I actually don’t know the complexity of the change within the Swift compiler itself.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Alex Gordon) #3

A coroutine library can be implemented in terms of the generators in Swift
2. Coroutines are different from generators in that they can send
information back to the subordinate function. This can be done using
additional ivars in the generator struct.

In a compiled language, Generator.yield() cannot be a library function, it
must be a statement or expression, as each yield is an exit point of the
function.

- Alex

···

On Sun, Dec 13, 2015 at 6:13 PM, David Waite via swift-evolution < swift-evolution@swift.org> wrote:

Because stackful coroutines quickly start to quickly approximate
threading, I didn’t think they were appropriate to propose at this time.
That said:

I think you would probably want something like Coroutine.create<String,()>
so that the String->() and ()->String interfaces of the two objects can be
generated. Likewise, in your example I believe a Coroutine-related protocol
instance should be passed in that exposes a yield(value:String) -> ()
method

Coroutines and generator functions both involve additional rules for
cleanup. Imagine a coroutine or generator which walks a file or network
stream, returning individual lines of text. The code using .resume() may
stop reading once they recognize the line they need or encounter an error,
but the system still needs to be able to reclaim the coroutine as well as
close/reclaim the local/network stream resources.

The references need to be set up in such a way that objects are reclaimed
in a predictable order, and defer blocks would probably be supported and
run, to make such control flow more obvious. This compiler support which
would be required whether you were doing (sequence) generator functions or
“full” coroutines. In the generator case, such cleanup needs to be moved to
the teardown of your state objects. It is possible some of the cleanup for
full coroutines would be shared with pre-existing thread termination
support.

Finally - any calls to yield might never resume, and it is possible your
code will transition between processors/parent threads on the subsequent
resume. This pushes me toward promoting a keyword vs using Coroutine.yield,
and restricting use of the yield keyword to make such behavior more obvious
(in the same way throws must be declared and try must be used when calling
an error-throwing method today)

-DW

On Dec 12, 2015, at 9:43 PM, Taras Zakharko via swift-evolution < > swift-evolution@swift.org> wrote:

Personally, I am agains generators (its quite specific syntactic sugar
that adds a lot of complexity), but I would be all for a comprehensive
coroutine library*. One can model it after Lua’s coroutines (
http://www.lua.org/pil/9.1.html), which works well with the existing
syntax. Your example becomes something like:

helloGenerator = Coroutine.create<()->String>({name:String -> () in
   Coroutine.yield(“Hello”)
   Coroutine.yield(name ?? “World”)
})

this generates a class instance with a resume ()->String? method that can
be used to retrieve the values. You can also pass values via resume (they
will be then available as results of coroutine.yield)

One can than use helloGenerator.resume() to get the values (which can be
easily wrapped in a sequence etc).

Benefits of this approach: no need for significant syntactic change
(although a coroutine keyword could be introduced instead of func to wrap
the above declaration), the coroutine functions are offloaded to a type
rather than syntactic construct, type safety is quite easy to preserve.
Still, its far from being a trivial thing to implement as it would require
support of continuations on the compiler level.

Cheers,

Taras

*Yes, current generators in Python are essentially coroutines but I think
it important to keep the terminology clean. Generators are intended first
and foremost as lazy sequence, well, generators. Coroutines are a much more
versatile construct.

On Fri, Dec 11, 2015 at 18:21 PM, David Waite via swift-evolution < > swift-evolution@swift.org> wrote:

Looking for feedback on crafting a proposal adding generator functions to Swift. I understand this will likely be a very involved proposal at the language level, although I actually don’t know the complexity of the change within the Swift compiler itself.

_______________________________________________

swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution