using channel to deliver result or error

6,737 views
Skip to first unread message

Ilyia Kaushansky

unread,
May 12, 2012, 8:13:08 PM5/12/12
to golan...@googlegroups.com
Hi,

I just realized that I can turn any blocking function that returns type ABC into a non-blocking function that returns "<- chan ABC". 

Many blocking functions block due to IO, and typically whereever there is IO there are errors. From my understanding, functions with errors should typically return (ABC, error). However, I can't transform such function into a function that returns "<- chan (ABC, error)", because channels are only able to deliver a single value. Thus, I need to create another struct that contains ABC and error fields. This is somewhat annoying (I've grown to like multi-variable returns).

Does anyone have any advice on how to proceed ? It seems like it would be fairly common to desire receipt of (result or error) via channel, but the language doesn't seem to help. Perhaps I'm missing something ?

Thanks,

ilyia


kortschak

unread,
May 12, 2012, 8:19:01 PM5/12/12
to golan...@googlegroups.com
If you want to do that, you can make a struct{Result, error} and send that or a pointer to it.

Ilyia Kaushansky

unread,
May 12, 2012, 8:30:16 PM5/12/12
to golan...@googlegroups.com
On Saturday, May 12, 2012 5:19:01 PM UTC-7, kortschak wrote:
If you want to do that, you can make a struct{Result, error} and send that or a pointer to it.

That's precisely what I was hoping to avoid. 

Dave Cheney

unread,
May 12, 2012, 8:30:40 PM5/12/12
to Ilyia Kaushansky, golan...@googlegroups.com
Two strategies I have used are

c := make(chan interface{})

result, err := doWork()
if err != nil { 
   c <- err
} else {
   c <- result
}

then

switch r := <- c; r.(type) {
case ResultType:
   ....
case error:
   ....
default:
   panic('unexpected type')
}

Or you can can define an anonymous struct

c := make(chan struct { ResultType; error })
result, err := doWork()
c <- struct { ResultType; error }{ result, err }

then

s := <- c
if s.error != nil {
....
}

(typed without the air of play.golang.org, mistakes are likely)

jimmy frasche

unread,
May 12, 2012, 8:33:56 PM5/12/12
to Ilyia Kaushansky, golan...@googlegroups.com
Use two channels:

func the_goroutine(vc chan T, ec chan error) {
v, err := the_func()
if err != nil {
ec <- err
}
vc <- v
}

Where you want to get the result:

select {
case v := <- vc:
...
case err := <- ec:
...

ikau...@google.com

unread,
May 12, 2012, 8:53:33 PM5/12/12
to golan...@googlegroups.com, Ilyia Kaushansky
I just tried this anonymous struct approach on play.golang.org and it looks fairly decent. Thank you Dave ! 

The extra complexity seems to be localized within the implementation of the function(which is good). I think I like this approach better than the other proposals in this thread. For the curious, here what this actually ended up looking like: http://play.golang.org/p/69-2pirZnB (unfortunately, the formatter does a rather terrible job)

ilyia

Kyle Lemons

unread,
May 13, 2012, 1:05:31 AM5/13/12
to jimmy frasche, Ilyia Kaushansky, golan...@googlegroups.com
I take a similar approach, but I utilize the fact that all channel operations are synchronization points.

var ret Type
errch := make(chan error)
go func() {
  r, e := Operation()
  ret = r // (A)
  errch <- e
}()

// do stuff
if err := <-errch; err != nil {
  //handle error
}
// after the sync, ret is guaranteed to observe the write marked // (A)

It's kinda ugly in this instance with a bunch of extra variables declared, but I find that it actually works pretty nicely in most "real world" code.

kortschak

unread,
May 13, 2012, 1:32:45 AM5/13/12
to golan...@googlegroups.com, Ilyia Kaushansky
I'm confused. How does the anonymous struct approach you've accepted differ from the suggestion that you were adamantly against?

Ilyia Kaushansky

unread,
May 13, 2012, 1:57:03 AM5/13/12
to golan...@googlegroups.com, Ilyia Kaushansky
On Saturday, May 12, 2012 10:32:45 PM UTC-7, kortschak wrote:
I'm confused. How does the anonymous struct approach you've accepted differ from the suggestion that you were adamantly against?

My apologies. I wasn't aware of "anonymous structs" when I read your response, and I assumed that your proposal required explicitly creating a new named type. 

Matt Joiner

unread,
May 13, 2012, 2:32:28 AM5/13/12
to golan...@googlegroups.com
An anonymous struct is a great idea here. Thanks for the suggestion Dave.
Reply all
Reply to author
Forward
0 new messages