A yield statement

50 views
Skip to first unread message

delfick

unread,
Nov 15, 2009, 8:34:39 AM11/15/09
to golang-nuts
Hello,

From what I can see, unless I'm missing something, to create a lazily
evaluated generator function you can do something like this

package main

import "fmt"

func Range(values chan int, lower, upper int) {
for i:=lower; i < upper; i++ {
fmt.Println("Range ", i);
values <- i;
}
close(values);
}

func main() {
values := make(chan int, 1);
go Range(values, 1, 20);
for j := range values {
fmt.Println("Loop ", j);
}
}


My suggestion becomes to introduce a yield statement to make this
process slightly more transparent.
So, the code becomes

package main

import "fmt"

func Range(lower, upper int) int {
for i := lower; i < upper; i++ {
fmt.Println("Range", i);
yield i;
}
}

func main() {
for j := range values() {
fmt.Println("Loop ", j);
}
}

What my idea says is that with the yield statement, the function
implicitly becomes a generator and calling it returns a channel which
you can then take values from.

This way : creating the channel, closing the channel and setting the
generator on a goroutine is handled for you.

...

Thankyou
Regards
Stephen

kyon

unread,
Nov 15, 2009, 9:39:19 AM11/15/09
to golang-nuts
I think so. We need yield statement!!

delfick

unread,
Nov 15, 2009, 10:02:19 AM11/15/09
to golang-nuts
hmm, google groups is being a bit weird, anyway, I got an email from a
Nathan Baum in my inbox (and the email says it was sent to ml as well,
but it's not on the web interface...)

On Sun, Nov 15, 2009 at 10:44 PM, Nathan Baum
<natha...@parenthephobia.org.uk> wrote:
> This second snippet seems to be missing any call to Range().
>

oops, meant

func main() {
for j := range Range(1, 20) {
fmt.Println("Loop ", j);
}
}


> So what you're saying, if I understand it correctly, is that when
> "range" is applied to a function call expression, it:
>
> 1. Makes a channel of the function's return type.

yeap

> 2. Invokes the function call in a goroutine, passing the channel as an
> special implied parameter.

without passing a channel, the channel is created for you

> 3. Returns the channel as its value.

yeap

Which also means you can then get values from it without using a loop
in a normal channel like fashion

func main() {
values = Range(1, 20);
first := <-values;
second := <-values;

fmt.Println("First and second : ", first, second):
}

...

:)

alodato

unread,
Nov 15, 2009, 11:26:28 AM11/15/09
to golang-nuts
You can already write a Range function that fulfills all of these
desires:

func Range(lower, upper int) chan int {
ret := make(chan int);
go func() {
for i:= lower; i< upper; i++ {
ret <- i;
}
close(ret);
}();
return ret;
}


On Nov 15, 7:02 am, delfick <delfick...@gmail.com> wrote:
> hmm, google groups is being a bit weird, anyway, I got an email from a
> Nathan Baum in my inbox (and the email says it was sent to ml as well,
> but it's not on the web interface...)
>
> On Sun, Nov 15, 2009 at 10:44 PM, Nathan Baum
>

delfick

unread,
Nov 15, 2009, 9:11:38 PM11/15/09
to golang-nuts
On Mon, Nov 16, 2009 at 12:26 AM, alodato <avery....@gmail.com>
wrote:
> You can already write a Range function that fulfills all of these
> desires:
>
> func Range(lower, upper int) chan int {
> ret := make(chan int);
> go func() {
> for i:= lower; i< upper; i++ {
> ret <- i;
> }
> close(ret);
> }();
> return ret;
> }
>
>


Ahhh, of course, yes.

Thankyou.

A yield statement would make that cleaner, but that's still very
nice :p :)

.....

Regards
Stephen

Charles Forsyth

unread,
Nov 15, 2009, 9:46:33 PM11/15/09
to golang-nuts
one advantage of making the channel explicit is that
you can pass it to other operations that take channels,
such as select, or send it to another process.

delfick

unread,
Nov 15, 2009, 9:52:48 PM11/15/09
to golang-nuts


On Nov 16, 10:46 am, Charles Forsyth <charles.fors...@gmail.com>
wrote:
> one advantage of making the channel explicit is that
> you can pass it to other operations that take channels,
> such as select, or send it to another process.

the same would happen in my idea...
it's just the channel becomes implicit.

ancientlore

unread,
Nov 16, 2009, 8:50:07 AM11/16/09
to golang-nuts
Is a channel so low overhead that it's fine for use with a generator,
that shouldn't necessarily require a goroutine to run? I think it
works but the implementation is quite different from a yield which is
more like an iterator.

Chas. Owens

unread,
Nov 16, 2009, 9:35:49 AM11/16/09
to ancientlore, golang-nuts
Did you see the portion of the video where Rob Pike demos chain.go?
It builds and tears down 10,000 channels in one and a half seconds on
a MacBook Air (http://www.youtube.com/watch?v=rKnDgT73v8s#t=43m40s).

--
Chas. Owens
wonkden.net
The most important skill a programmer can have is the ability to read.

ancientlore

unread,
Nov 16, 2009, 11:31:43 AM11/16/09
to golang-nuts
That's pretty impressive - I guess there is no need to add another
language feature if that covers it efficiently.

On Nov 16, 9:35 am, "Chas. Owens" <chas.ow...@gmail.com> wrote:

Rob 'Commander' Pike

unread,
Nov 16, 2009, 11:43:08 AM11/16/09
to Chas. Owens, ancientlore, golang-nuts

On Nov 16, 2009, at 6:35 AM, Chas. Owens wrote:

Did you see the portion of the video where Rob Pike demos chain.go?
It builds and tears down 10,000 channels in one and a half seconds on
a MacBook Air (http://www.youtube.com/watch?v=rKnDgT73v8s#t=43m40s).

It's 100,000, not 10,000, and don't forget about creating and tearing down the goroutines.

Regarding the question of whether channels are cheap enough for iterators: they're nowhere near as cheap as using an integer to index an array, so I wouldn't use them for every iteration that came my way.  I do want to see the implementation get to the point that such use is about as expensive as a coroutine (sic) switch most of the time, but it's not even that good now.

-rob

Reply all
Reply to author
Forward
0 new messages