It's not uncommon to see code like this:
package main
import (
"github.com/hashicorp/go-multierror"
)
type server struct{}
func (s *server) Run() error {
g := new(multierror.Group)
g.Go(
func() error {
// ...code to do some work here...
return nil
},
)
g.Go(
func() error {
// ...code to do some MORE work here...
return nil
},
)
return g.Wait()
}
func main() {
s := server{}
if err := s.Run(); err != nil {
panic("error while running")
}
}
However, there is a subtle bug here. The main function will always panic, despite no error being returned by any of the Goroutines managed by the group g. This is due to the fact that Go treats interfaces as "fat pointers". See:
A "fix" is to add the following nil check to the Run method above:
func (s *server) Run() error {
g := new(multierror.Group)
g.Go(
func() error {
// ...code to do some work here...
return nil
},
)
g.Go(
func() error {
// ...code to do some MORE work here...
return nil
},
)
if err := g.Wait(); err != nil {
return err
}
return nil
//... or alternatively: return g.Wait().ErrorOrNil()
}
This is certainly not intuitive, and relies on type-inference to solve the problem. I've added a test to my fork of this repo to clearly demonstrate the issue:
My question - is there a good reason why Group.Wait returns *Error instead of just error, which is more idiomatic? Returning error would eliminate this weirdness seen here.
It's not uncommon to see code like this:
However, there is a subtle bug here. The
mainfunction will always panic, despite no error being returned by any of the Goroutines managed by the groupg. This is due to the fact that Go treats interfaces as "fat pointers". See:A "fix" is to add the following nil check to the
Runmethod above:This is certainly not intuitive, and relies on type-inference to solve the problem. I've added a test to my fork of this repo to clearly demonstrate the issue:
My question - is there a good reason why
Group.Waitreturns*Errorinstead of justerror, which is more idiomatic? Returningerrorwould eliminate this weirdness seen here.