Golang: Passing channels through empty interfaces - go

I'm trying to do something that seems like it should be trivial until I read up and now it seems like it should be really complex. ;-)
I've knocked up a test pattern to illustrate:
http://play.golang.org/p/Re88vJZvPT
At the most basic I'm trying to have a function that can read data from a channel and spit it out on another one. Easy. The test does this as long as you use the pusher function shown.
However the problem with this is that doing it this way I would need a different pusher function for each type of data I want to push through it.
Now I've done similar things in the past with an empty interface as nothing in the pusher code cares about what's in the data structure. What I can't figure out is when I'm dealing with channels of an un-cared-about data structure.
To illustrate the concept of what I'm trying to achieve please see the function pusher_naive_generic.
However that doesn't work either so more reading up implied the way to do it was making use of reflection and finally you see my pusher_reflect_generic function(obviously this won't achieve the same intended function as the others it's showing where I got to before getting stuck).
Which still fails because I can't get from an interface that contains a chan to the structure read from that chan.
Hopefully the code makes more sense of what I'm trying to achieve than my words actually do. I can make all of this work by explicitly coding for every type, but what I can't figure out how to do is code it for any future type.

If I have understood your question correctly, then this might be the solution:
http://play.golang.org/p/xiDO7xkoW4
func forwardChannel(i interface{}, o interface{}) {
it, ot := reflect.TypeOf(i), reflect.TypeOf(o)
if it != ot {
panic("forwardChannel: both arguments must be of the same type")
}
iv, ov := reflect.ValueOf(i), reflect.ValueOf(o)
for {
v, k := iv.Recv()
if !k {
break
}
ov.Send(v)
}
ov.Close()
}
Note that Recv, Send and Close panic if i and o are not channels.

Related

Wrap GoRoutine Creation to also contain pprof label

In my code there are various types of functions with a lot of user defined parameters and return types. Most of them run in parallel as go routines. In order to be able to efficiently debug them, I want to add labels.
I went through this link on using profile labels, find go routines during debugging.
However, if I do it the way they've mentioned, ie. call the desired function inside pprof.Do, then this would mean that I would have to add this redundant piece of code everywhere.
Old code:
go executeMeAsGoRoutine(arg1 sometype, arg2 sometype)
New Code based on the links above:
go func(args1 type1, args2 type2, args3 type3, args4, type4) {
labels := pprof.Labels("some label", "some more label", "args1",strconv.Itoa(int(100)))
pprof.Do(context.Background(), labels, func(_ context.Context) {
//function that was to be called.
executeMeAsGoRoutine(arg1, arg2, arg3, arg4)// Use args1 or args2
})
}(page, i)
However most of my functions have different arguments and custom return types. If I were to enhance each go routine I will have to repeat the above code everywhere. Wherever, I am calling go runThisFunctionInGoRoutine(), I'll also have to add outer anonymous go routine, followed by pprof.Labels, followed by pprof.Do everywhere. This will lead to a lot of unnecessary code repetiton. There are already so many places where there are different go routines created.
I was hoping if I could make a generic function that would WRAP the go routine creation call as well as label creation and then does pprof.Do for me.
Can someone suggest how to do that? The source of problem is that the functions that should run as go routines are different and have different arguments.
I envision some api like:
makeGoRoutineWithLabel(labels string, functionToRun, argumentsToSupply).
NOTE: functionToRun is different each time with argumentsToSupply being different as well.
Can anyone suggest how to do this without repeating the code? A generic go routine creation wrapper which also provides a provision to add labels along.
Instead of go createGoRoutine, its something like createAGoRoutineWithLabels.

How to write throws(in java) like code in golang

Is there any way in Golang for a func to "throws"(like in java) an error?
Through Which I can specify , my func may return error and caller needs to handle the error.
I am just trying to mimic "throws" like approach which we have in java.
May be this is very basic elementary type question , sorry for that , I am new in golang.
Note : I have tried panic, defer, recover , but problem is that if both the functions/methods is in same go file it is working properly , but if suppose both(caller and func) are different go file it is starting a different go routine , "defer" at caller level is not working properly.
I guess this approach is not also equivalent like "throws" , where function provider is not handling the error but caller did that , and take the recovery action. Function body provider just specify it may return some exception and caller have to handle the exception.
Thanks in advance...
No, you cannot do that. Go does not support throwing exceptions.
As you have noticed, you can panic and recover, but it's not the same thing.

How can I use dynamic errors while retaining comparability for testing?

In go I often use
func MyFunc(s someInterface) error {
err := OtherFunc(s)
return fmt.Errorf("something wrong: %s", err)
}
So I lose the original error value, because I just take the error string and forge it into a new error. That is what I mean with dynamic errors.
Now consider a test for MyFunc():
func TestMyFunc(t *testing.T) {
s := mockSomeInterface()
testErr := MyFunc(s)
if testErr != interfaceSpecificErrorValue {
t.Errorf("fail")
}
}
What would I use for interfaceSpecificErrorValue (which is specific to someInterface in this example)? Or how could I make this testable?
I understand that I can solve this by defining all my possible errors beforehand and give them a constant value. What I am interested in is if there is another way to achieve this, because I like the hierarchical error messages that you can dynamically build up using fmt.Errorf("...: %s, err). There must be a good way to keep the error hierarchy without losing the original value.
(Comparing the output of the Error() method is a possibility, but not a good one.)
My preliminary answer to this is: In Go currently there is no canonical way to achieve nested errors with comparable error values.
After reading the offical documents and blog posts on error handling again, quite some source code from standard libraries, and finally this proposal: https://github.com/golang/proposal/blob/master/design/go2draft-error-values-overview.md, I decided I will keep my error types simple and static and wait for Go 2 to offer a better way.

Mapping external errors to domain errors in golang

I have a service type called ComputeService which implements certain domain logic. The service itself depends on implementation of an interface called Computer which has a method Computer.Compute(args...) (value, error). As shown, Compute itself might return certain errors.
ComputeService needs to send appropriate errors from a set of domain-errors with proper domain-error code so that translations can be done and also clients can handle errors appropriately.
My question is, should the Computer implementations be wrapping their failure in domain-errors or should ComputeService do this. If ComputeService is the one doing it, then it will have to know about different errors returned by different implementations of Computer interface which in my opinion breaks the abstraction. Both ways are demonstrated below:
package arithmetic
type Computer struct {
}
func (ac Computer) Compute(args ....) (value, error) {
// errors is a domain-errors package defined in compute service project
return errors.NewDivideByZero()
}
OR
package compute
type Service struct {
}
func (svc Service) Process(args...) error {
computer := findComputerImplementation(args...)
val, err := computer.Compute(args...)
if err != nil {
if err == arith.ErrDivideByZero {
// converting an arithmetic computer implementation
// specific error to domain error
return errors.NewDivideByZero()
} else if err == algebra.ErrInvalidCoEfficient {
// converting an algebraic computer implementation
// specific error to domain error
return errors.NewBadInput()
}
// some new implementation was used and we have no idea
// what errors it could be returning. so we have to send
// a internal server error equivalent here
return errors.NewInternalError()
}
}
Implementors of Computer should respond with the domain errors, since they're the closest ones to the action and best able to determine what an error is. Like you said, having that logic in ComputeService breaks the abstraction. If you need mapping code from specific Computer errors to domain errors, create wrapper structs that separate the main logic from that error wrapping code.
To keep internal error context, just embed the original error in the domain error and make IsSpecificDomainError helpers.
type MyDomainError struct {
Err error
}
func NewMyDomainErr(err error) error {
return &MyDomainError{err}
}
func IsMyDomainError(e error) bool {
_, ok := err.(*MyDomainError)
return ok
}
To keep internal error context, just embed the original error in the domain error
This can use Wrapping errors, which are on their way for Go 1.13 (Q4 2019), from issue 29934, as detailed here.
err.Is():
As Russ Cox mentions:
I think we all agree that strings.Contains(err.Error(), "not found") is fragile code.
I hope we also agree that we'd prefer to see code like errors.Is(err, os.ErrNotExist).
But the point is that in many cases, it is essential to future evolution of a package to keep callers from depending on a particular error result satisfying errors.Is(err, os.ErrNotExist), even if that is the underlying cause in today's result.
It's like looking at an unexported field or comparing error text - it's a detail that might change.
And while strings.Contains looks and is fragile, errors.Is does not look nor should be considered fragile.
If we are to avoid it being fragile, then we need to provide a way for packages to report detail without letting clients test for it. That way is errors that can't be unwrapped.
err.As():
var pe *os.PathError
if errors.As(err, &pe) {
use(pe)
}
%w:
func inner() error { return errors.New("inner error") }
func outer() error { return fmt.Errorf("outer error: %w", inner()) }
fmt.Fprintf("%+v", outer())
// outer error:
// /path/to/file.go:123
// - inner error:
// /path/to/file.go:122
The current status for Go 1.13:
Just stating what I see as the compromise solution offered by the team:
fmt.Errorf is currently being used extensively to wrap errors and return a new (opaque) error (as in you cannot access the underlying error).
'%w' can now be used to explicitly opt-in to return an error that can be unwrapped.
errors is designed as a base package with no dependencies so that every package can depend on it.
the team agrees to punt on the areas that there is broad disagreement, and want to release just enough (errors.Is, errors.As, extension to way most folks wrap errors) so folks can achieve things.
Generics is not here yet, and we do not know when it will come: the heated discussion on that will make this one on "error 2 values" look like child's play.
errors.Is and errors.As are clean and concise enough to be comfortable for a long time.
Most of the contentious things have been punted to go 1.14.
Wrapf cannot live in errors as it is a base package.
Wrapf means team MUST decide on what happens when a nil error is passed: Punt on it.
Wrap may conflict with ideas being considered for localization, internationalization, etc.
ErrorFormatter and ErrorPrinter have not yet gotten much deeper usage and have warts. Punt.

What's the point of creating one-way channels in Go

In Go one can create one-way channels. It's a very convenient feature in case of one want to restrict a set of operations available on the given channel. However, as far as I can see, this feature is useful only for function's arguments and variable's type specification, while creating one-way channels via make looks strange for me. I've read this question, but it's not about creating read (or write)-only channels in Go, it's about usage in general. So, my question is about use cases of the next code:
writeOnly := make(chan<- string)
readOnly := make(<-chan string)
Theoretically you can use write only channels for unit testing to ensure for example that your code is not writing more than specific number of times to a channel.
Something like this: http://play.golang.org/p/_TPtvBa1OQ
package main
import (
"fmt"
)
func MyCode(someChannel chan<- string) {
someChannel <- "test1"
fmt.Println("1")
someChannel <- "test2"
fmt.Println("2")
someChannel <- "test3"
fmt.Println("3")
}
func main() {
writeOnly := make(chan<- string, 2) // Make sure the code is writing to channel jsut 2 times
MyCode(writeOnly)
}
But that would be pretty silly technique for unit testing. You're better to create a buffered channel and check its contents.
One of the main reason that people use types (especially in Go) is as a form of documentation. Being able to show that a channel is read-only or write-only, can help the consumer of the API have a better idea of what is going on.

Resources