5 ms·
Coroutines are one thing that i'd probably prefer language support for rather than a library. x := co func(){ var z int for { z
by chrsig 3y ago
Coroutines are one thing that i'd probably prefer language support for rather than a library.
x := co func(){
var z int
for {
z++
yield z
}
}
y := x()
for y := range x {
...
}
or something to that effect. It's cool that it can be done at all in pure go, and I can see the appeal of having a standard library package for it with an optimized runtime instead of complecting the language specification. After all, if it's possible to do in pure go, then other implementations can be quickly bootstrapped.
My $0.02, as someone that uses go at $work daily: I'd be happy to have either, but I'd prefer it baked into the language. Go's concurrency primitives have always been a strength, just lean into it.
- 38 3y agowow that is horrible. none of that is intuitive, which is one of Go strength. you would need to specific learn the Go semantic of coroutine to have any chance of writing or even reading code like this.
- sk0g 3y agoGoroutines and channels aren't intuitive either. You learn them and become familiar with them over time, at which point they become intuitive __for you__.
- 38 3y agoactually I get it now. the issue is that OP was giving TWO different examples of use, pulling a single value versus multiple. they should have clarified.
- chrsig 3y agoYes, on review, I should have made two examples instead of combining them. Thanks for persevering through my brevity and reaching understanding :)
- dboreham 3y agoThey're totally intuitive if you were an Occam programmer.
- sk0g 3y agoSo it's intuitive because you are familiar with those concepts. I don't see how that goes against what I said.
- kissgyorgy 3y agoYes, you need to learn language features in order to use the language, shocker!
- 12345hn6789 3y agoI've written go for a year or so. That looks close to go code I look at every day. I wouldn't be surprised if it was in the language.
- MichaelMoser123 3y agoyou need language support for coroutines - what happens when the stack runs out in one of the coroutine? With a library solution you would have to kill the co-routine, or kill the program. If you want the stack to grow transparently, then that can only be done by the generated code, it has to watch stack usage and then grow the stack on demand (i think you have something like that with goroutines) Well, maybe a library solution could possibly have a guard page at the end of the stack. When that one is reached, then you could try to grow the stack in an error handler. (but that would probably not work, if you have taken a pointer to some stack variable)
- hgsgm 3y agoYou don't need language support for coroutines if you have language support for relocatable/chunkable stack, which Go has.
- uhura 3y agoI would prefer to add a `yield` param to functions so it can better interact with the current type system. This means that for a function to yield, it needs to have the so called `yield` param and you can only yield inside a yield function functions with the same yield signature or does not contain a signature at all. So the example would be rewritten into something like: x := func(:z int) { for { z++ :- z } } for y := range x() { ... } The : adds the yield signature and :< yields the value. Functions that only yield a value `X` would just have the `: X` or `: name X`. To accept a value of type `Y` in the resume the signature would change to `:[Y] X` or `:[Y] name X`. Accepting is weak, so if something expects a yielding function that resumes with Y and yield X, yielding functions that only yield X without a resume should also be accepted. Consider the following code example: func filter[T comparable](it func(:T), f func(T) bool, :T) { for v := range it { if f(v) { :- v } } } func map[T](arr []T, :T) { for _, v := range arr { :- v } } for v := range filter(map({1, 2, 3}), func(x) { return x < 3 }) { print(v) } Special functions in a co package could give resume and New functionality to keep the go style. A basic counter could be written like this: func counter(:[bool]c int) { for { if ! :- c { break } c += 1 } } A func that counts twice could be as simple as: func countTwice(:[bool]c int) { count() count() } To interact with the resume value the range syntax could be expanded to something like: for c := range count() { if c > 10 { -: false } -: true print(c) } Range would resume with a default zero value if the range does not pass a value to -:.
- gpderetta 3y agoSure, as long as I can close over a yield object. There is no reason for filter and map to know that the last function parameter takes a continuation.
- uhura 3y agoBut then, how could you guarantee type safety? This yield is not an object, it is handling the execution context to another stack.
- 3y ago