Callback parameter defined using interface, called using implementation - go

What I'm trying to do:
I have a library package which defines a few types, all implementing a given interface. Throughout the code, there are callbacks involved, and instead of writing the callback type everywhere I defined a type for it.
type Foo interface {
Bar()
}
type MyCallback func(f Foo)
type CoolFoo int
type BadFoo int
func (cf *CoolFoo) Bar(cb MyCallback) {
}
func (bf *BadFoo) Bar(cb MyCallback) {
}
Then later from client code using that library, I want to call using callbacks. If I call it by using the interface type it works:
cf := &CoolFoo{}
cf.Bar(func(f packageName.Foo) {
})
But I would rather have more self documenting code, and proper type hinting in my IDE, so I try to call it using the implementor type, such as this:
cf := &CoolFoo{}
cf.Bar(func(f packageName.CoolFoo) {
})
Which fails to compile, with the error:
cannot use func literal (type func(packageName.CoolFoo)) as type
packageName.MyCallback in argument to cf.Bar
Is it not possible, or am I making some dummy mistake ? I'm not very experienced in go dev, and I've tried looking around, but couldn't find the solution here.
What I've found is passing it as a Foo or an interface{} and then casting in the callback to what I want, but I would like to avoid it as it feels messy
Thanks for any help

The function signature is func(f Foo), so that is exactly what must be passed. The reason is simple: if your method expects a callback function of that signature, it can pass in any type that implements Foo. If you passed in a function that only accepted CoolFoo, the caller could still pass in BadFoo, because the types you've defined allow it. Thus, the compiler requires that the types match precisely. Likewise, if your callback function tries to cast to a concrete type, but that isn't the type that was passed to it, it will fail, because you're making an assumption that isn't supported by the code.
If your callback will only pass in CoolFoo, maybe that should be the type you use in the signature. If CoolFoo and BadFoo will each only pass in their respective types to their callbacks, maybe you need two different callback signatures. If they really are interchangeable, then the case you describe (a function taking CoolFoo specifically) isn't a problem with the language, it's a problem with your design.

Related

Golang wrap calls to package methods generically [duplicate]

I want to write a single function that can add certain fields to Firebase message structs. There are two different types of message, Message and MulticastMessage, which both contain Android and APNS fields of the same types, but the message types don't have an explicitly declared relationship with each other.
I thought I should be able to do this:
type firebaseMessage interface {
*messaging.Message | *messaging.MulticastMessage
}
func highPriority[T firebaseMessage](message T) T {
message.Android = &messaging.AndroidConfig{...}
....
return message
}
but it gives the error message.Android undefined (type T has no field or method Android). And I can't write switch m := message.(type) either (cannot use type switch on type parameter value message (variable of type T constrained by firebaseMessage)).
I can write switch m := any(message).(type), but I'm still not sure whether that will do what I want.
I've found a few other SO questions from people confused by unions and type constraints, but I couldn't see any answers that helped explain why this doesn't work (perhaps because I'm trying to use it with structs instead of interfaces?) or what union type constraints are actually useful for.
In Go 1.18 you cannot access common fields1, nor common methods2, of type parameters. Those features don't work simply because they are not yet available in the language. As shown in the linked threads, the common solution is to specify methods to the interface constraint.
However the the types *messaging.Message and *messaging.MulticastMessage do not have common accessor methods and are declared in a library package that is outside your control.
Solution 1: type switch
This works fine if you have a small number of types in the union.
func highPriority[T firebaseMessage](message T) T {
switch m := any(message).(type) {
case *messaging.Message:
setConfig(m.Android)
case *messaging.MulticastMessage:
setConfig(m.Android)
}
return message
}
func setConfig(cfg *messaging.AndroidConfig) {
// just assuming the config is always non-nil
*cfg = &messaging.AndroidConfig{}
}
Playground: https://go.dev/play/p/9iG0eSep6Qo
Solution 2: wrapper with method
This boils down to How to add new methods to an existing type in Go? and then adding that method to the constraint. It's still less than ideal if you have many structs, but code generation may help:
type wrappedMessage interface {
*MessageWrapper | *MultiCastMessageWrapper
SetConfig(c foo.Config)
}
type MessageWrapper struct {
messaging.Message
}
func (w *MessageWrapper) SetConfig(cfg messaging.Android) {
*w.Android = cfg
}
// same for MulticastMessageWrapper
func highPriority[T wrappedMessage](message T) T {
// now you can call this common method
message.SetConfig(messaging.Android{"some-value"})
return message
}
Playground: https://go.dev/play/p/JUHp9Fu27Yt
Solution 3: reflection
If you have many structs, you're probably better off with reflection. In this case type parameters are not strictly needed but help provide additional type safety. Note that the structs and fields must be addressable for this to work.
func highPriority[T firebaseMessage](message T) T {
cfg := &messaging.Android{}
reflect.ValueOf(message).Elem().FieldByName("Android").Set(reflect.ValueOf(cfg))
return message
}
Playground: https://go.dev/play/p/3DbIADhiWdO
Notes:
How can I define a struct field in my interface as a type constraint (type T has no field or method)?
In Go generics, how to use a common method for types in a union constraint?

What's the purpose of ProtoMessage method?

when I generate go code from a protocol buffer file, I noticed that each of the generated structs implement the Message interface, https://github.com/golang/protobuf/blob/master/proto/lib.go#L277
For an example of the code that is generated, see https://github.com/google/go-genproto/blob/master/googleapis/rpc/status/status.pb.go#L97
Clearly, the other methods on Message interface, String() and Reset(), have an obvious purpose and the concrete implementation example makes that clear. However, I don't understand the purpose of the ProtoMessage() method. The method takes no parameters and returns no arguments, so why is it there?
Quoting from official doc: Protocol Buffers: Go Generated Code:
Given a simple message declaration:
message Foo {}
the protocol buffer compiler generates a struct called Foo. A *Foo implements the Message interface. See the inline comments for more information.
type Foo struct {
}
// Reset sets the proto's state to default values.
func (m *Foo) Reset() { *m = Foo{} }
// String returns a string representation of the proto.
func (m *Foo) String() string { return proto.CompactTextString(m) }
// ProtoMessage acts as a tag to make sure no one accidentally implements the
// proto.Message interface.
func (*Foo) ProtoMessage() {}
Note that all of these members are always present; the optimize_for option does not affect the output of the Go code generator.
This is a (similar) technique described in Go official FAQ: How can I guarantee my type satisfies an interface?
If you wish the users of an interface to explicitly declare that they implement it, you can add a method with a descriptive name to the interface's method set. For example:
type Fooer interface {
Foo()
ImplementsFooer()
}
A type must then implement the ImplementsFooer method to be a Fooer, clearly documenting the fact and announcing it in godoc's output.
type Bar struct{}
func (b Bar) ImplementsFooer() {}
func (b Bar) Foo() {}
Most code doesn't make use of such constraints, since they limit the utility of the interface idea. Sometimes, though, they're necessary to resolve ambiguities among similar interfaces.
So the ProtoMessage() method basically has 2 purposes:
The main purpose is as documented in the generated code: to make sure you don't pass a value for protobuf serialization / deserialization which otherwise (without this method) would implement the proto.Message interface but is not a "real" protobuf message value:
ProtoMessage acts as a tag to make sure no one accidentally implements the proto.Message interface.
And it also documents the fact that the type is a (implements) Message. This may not have a real value at first as the code is generated and you should not bother much with it, but code analyzers and Go IDE's may make good use of it; and it also appears in generated docs.

Is unnamed arguments a thing in Go?

I am writing a parser in Go for Go, and to test it I downloaded a bunch of files from github projects.
In https://github.com/andlabs/ui I bumped into a file containing this piece of code:
func moveLabel(*Button) {
from := movingCurrent
to := 0
if from == 0 {
to = 1
}
movingBoxes[from].Delete(0)
movingBoxes[to].Append(movingLabel, false)
movingCurrent = to
}
It confuse me a bit to see a pointer to a Button without a name as a function argument, which makes it impossible to reference from inside the function.
However, it seems to be syntactically correct given that the compiler doesn't complains.
What is the purpose of unamed functions arguments in Go?
Unnamed parameters are perfectly valid. The Parameter declaration from the spec:
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
As you can see, the IdentifierList (the identifier name or names) is in square brackets, which means it's optional. Only the Type is required.
The reason for this is because the names are not really important for someone calling a method or a function. What matters is the types of the parameters and their order. This is detailed in this answer: Getting method parameter names in Golang
Generally you name variables and parameters so that you can refer to them.
When you don't name something, it's because you don't want to refer to it.
So the question should rather be: Why would I not want to refer to a parameter?
For example because the parameter "is there" (it is passed), but you don't need it, you don't want to use it. Why would it be there if I don't need it?
Because someone or something dictates for specific parameters to be there. For example you want to implement an interface, or you want to pass a function value whose signature is defined by the function type that is expected.
Let's see an example. We have the following MyWriter interface:
type MyWriter interface {
Write(p []byte) error
}
A simplified io.Writer which only returns an error, but does not report the number of bytes written. If you'd want to provide an implementation which just discards the data (similar to ioutil.Discard), then the implementation does not use (does not need to use) its argument:
type DiscardWriter struct{}
func (DiscardWriter) Write([]byte) error { return nil }
And that's all: we don't use the receiver, we don't use the argument. Both can be unnamed. And the implementation does exactly what it should.
Doing so (using unnamed parameters) also documents that the value is not used / referred to.
Another reason can be to provide forward compatibility. If you release a library, you can't change or extend the parameter list without breaking backward compatibility (and in Go there is no function overloading: if you want 2 variants with different parameters, their names must be different too). So you may declare an exported function or method with additional parameters early, but since you don't use them yet, you may leave them unnamed. An example of this is detailed in this answer: Why does Go allow compilation of unused function parameters?
One thing to note here is that you can't mix named and unnamed parameters. If you name some, you must name all. If you don't need all, you may use the blank identifier like in this example:
A simple web server which responds with the "Hello" text to all requests:
http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello")
})
panic(http.ListenAndServe(":8080", nil))
The handler function sending back the "Hello" text only uses the response writer w, but not the request structure, so the blank identifier is used as its name.
Another related question:
Why must we declare a variable name when adding a method to a struct in Golang?
Also somewhat related, but regarding using / naming returned values:
Return map like 'ok' in Golang on normal functions
And regarding getting method / function parameter names:
Getting method parameter names in Golang
Unnamed parameters are valid but not referenceable.
They're just for satisfaction of interfaces and signatures.
The purpose of unnamed function arguments is for arguments (which are local variables of the function) which are not referred to in the function's code, and therefore do not need a name. An interesting note about anonymous variables is that they are actually used more commonly than you may think. In Go, a function's return value(s) are usually listed as types, but actually they are also local variables of the function which can be named and manipulated.
See this example in the "Effective Go" page on golang.org
https://golang.org/doc/effective_go.html#named-results
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}

How to make this Go abstract type work?

package main
import "fmt"
type IA interface {
A()
B()
}
type AbsA struct {
IA
}
type CA struct {
AbsA
}
func (a CA) B() {
fmt.Println("Show B")
}
func (a AbsA) A() {
fmt.Println("Show A")
a.B()
}
func t7() {
var a IA
a = CA{}
a.A()
}
func main() {
t7()
}
Running this will get a nil pointer panic, because when AbsA calls B(), it will use the embedded IA, but IA is an interface.
Is there any way to make this work?
EDIT
I try to make a abstract super class, AbsA only implement part of interface, but it need to use other functions,A is a subclass of AbsA, only implement the rest part of interface.
But this looks bad, is there any other way to do this ? actually , I just want to do something like this
func (a IA)A(){
fmt.Println("Show A")
a.B()
}
but go can not use a interface as a receiver.
I don't know what you're trying to accomplish, but if you're defining structs with embedded interfaces, you need to initialize them.
http://play.golang.org/p/C32yWfNDRp
var a IA
a = CA{
AbsA: AbsA{
IA: CA{},
},
}
a.A()
If you're expecting OOP inheritance behavior, Go doesn't provide that. Embedding is only a form of automatic delegation.
No, at least not as you have it designed here. I'm not entirely sure what you're trying to accomplish but this is a very very poor use of embedding. The reason it doesn't work is because the CA type relies on the embedded AbsA type for method A() which then calls a 'method b' but the only actual implementation of B() has CA as the receiving type so once you've calling into the embedded types implementation of A() it can't call back up to the embedding types implementation of B().
You're treating embedding as if it's a two way street but in reality the embedding type knows all the methods on it's embed and the embed knows nothing about the embeddor. In my personal opinion, this should generate a compiler error. Perhaps in a future release it will (if I can tell at compile time that you will get a run-time error 100% of the time the compiler should able to too, right?).
As it is now you either need to implement B() with a receiver of type Absa or add another implementation of A() with a receiver of type CA. I'm not really sure what you're trying to accomplish so I can't say what the best course of action is. Note that if I were relating this to traditional OOP inheritance I would describe your code as attempting to access properties of a child class from within a parent class, clearly it's not possible. Absa will never be able to call up to an implementation of B() defined for the type embedding it. Just like trying to use a method defined on an inheriting type from the parent would never work or make sense only in most of the OOP languages you would get a compile time error.

Statically typed definitions vs dynamic lookup

On the book The Go Programming Language Phrasebook said:
If you require performance, then you can use statically
typed definitions and avoid the dynamic lookup.
If you require flexibility, then you can use the
late binding mechanism of interfaces
Can someone explain me what "statically typed definitions" and "dynamic lookup" are for methods and functions in Go?
Imagine that we have the following code:
type A struct {}
func (a A) Foo() {
fmt.Println("Foo called")
}
type I interface {
Foo()
}
I can now create a variable of type A and call this method:
a := A{}
a.Foo()
The compiler knows the static type of the variable, so knows that the method call refers to the A.Foo method. So it can compile the above code to use a direct call to A.Foo, which will be as fast as a normal function call.
If instead we use a variable of type I, things are different:
var i I = A{}
i.Foo()
The variable i can hold any type that has a Foo method. In this particular case it is holding an A value, but won't necessarily know this at compile time. So instead the compiler generates code to check the dynamic type of i, look up the associated Foo method and finally call that method. This form of dispatch is slower than the first, but has the benefit the code will work for any type implementing the interface.
This is similar to C++'s distinction between virtual and non-virtual methods, except rather than the type of dispatch being fixed for a method at its definition, it depends on the type of variable you use in Go.
What the book refers to when it says using static types is using non interface types:
func Foo(v int, s string) { ... }
The other option is using interface:
func Bar(a interface{}, b interface{}) { ... }
Because with the first option, Go will know at compile time what type of value the function will retrieve (int and string in this case), it will compile the code specifically for those types.
With the second option, you will have to use reflection at runtime in order to know the values contained in the interfaces. This is a bit of overhead, but it allows you to pass different types of values as parameters to the function, thus being more dynamic.
Further reading: Laws of Reflection in Go

Resources