in the linked playground example, I define a type:
type DoMap map[int]func(Doer) string
Where Doer
in an interface type that I define.
I implement the interface on a concrete type MyDoer
. I'd like to be able to construct a DoMap
where entries into that map contain functions like both of the following:
func(Doer) string // this works
func(*MyDoer) string // this doesn't
func(MyDoer) string // more-or-less the same idea, also doesn't
I can't, and although it's obvious they are different types, I wonder why I can't since function ensures I have to provide a MyDoer
which implements Doer
.
Isn't that enough to ensure I will fulfill my contract with the function?
Is there another way of achieving this?
https://play.golang.org/p/sJ2Rg3neL7
Some comments are of the form "they are different" "that's the spec" but I can pass a MyDoer
to a function that accepts a Doer
- if the interface is implemented: why does putting it into a map change the result?
There's a request to explain the "real problem" and a question of why I can't just use a map of types. I'll try best I can:
DoMap
cannot be a map of types. I am writing a library that allows developers to succinctly define state machines, which succeed or fail to transition, based on the output of a developer written function (business logic) that accepts a developer defined type (business message). the library exists to ensure that the series of transitions can be serialized and recorded elsewhere and subsequently verified by third party users of the library. I didn't say all that originally, because it misses the point - there isn't a simple answer.
Now I feel like I am annoying everyone with my impertinent questions, and since I don't exactly have Rob Pike on speed dial, I'll probably delete this, unless some one is willing to trust that I need to do what I need to do, and suggest something.
You haven't outlined a concrete problem (the why). This makes it hard to suggest alternatives, because it looks like you're trying to recreate another language in go.
In order of preference, you can use the type system as intended:
type DoMap map[int]func(Doer) string
type Doer interface {
Do() int
AlsoDo() int
}
https://play.golang.org/p/uPzoOZiLQG
Or you can bypass the type system of course:
type DoMap map[int]interface{}
https://play.golang.org/p/lfKPkwhOGa
But I wouldn't recommend that - better to work with the tools the language gives you, rather than trying to bend them out of shape.
The intent of the interface is to advertise a contract about the functions - they require this of their argument, and no more. But then you also want to call AlsoDo on the argument, so if you want to do that, put it in the contract. Then all will work as you intend. The contract for the function should be published next to the function as in your example, it should be under your control.
[EDIT] Finally, if you don't control the types passed in, perhaps you should rethink the idea of your map. It could be a map[int]Doer where Doer is an interface (which you should control). This lets you advertise what you require in your library, and users put whatever type they want in there (with whatever other dependencies they want).
// Library
type DoMap map[int]Doer
type Doer interface {
Do() int
}
// Client
type MyDoer struct {
myint int
}
func (d *MyDoer) Do() int {
fmt.Println(d.AlsoDo())
return d.myint + 1
}
func (d *MyDoer) AlsoDo() int {
return d.myint + 2
}
https://play.golang.org/p/cs01C8bSKo
[EDIT2] Final edit, if building an fsm management chain, you might find this little project inspirational. It should definitely be doable without much trouble, just not exactly as in your first attempt of a map of function which can take any type: