Function Types with Equivalent Interfaces

847 views
Skip to first unread message

Damien Whitten

unread,
Jun 25, 2014, 7:33:27 AM6/25/14
to golan...@googlegroups.com
Hi Gophers,

I've got myself confused with Function Types. 
There are two exactly equivalent interfaces, and it seems a function which takes the first isn't able to be used to satisfy the function type of the second.

In this trivial example, I'd just use the same interface, but in the real example the interfaces are split into two packages.

Possible solutions:
- One 'master' package the other depends on
- One 'interfaces' package
- Functions which convert between the two 

So the questions I have: 
- Is there an 'easy way' - like a missing 'type assertion' or other language feature I am missing which would make this code work or?
- Is there a way to do something similar to this so those interfaces can exist in two packages which don't depend on each other? 
- And... would this make sense as a language feature?

package main

type Eggplant interface {
Peel()
}

type Aubergine interface {
Peel()
}

func main() {

var au Aubergine
var ep Eggplant

au = ep
ep = au // Just checking, they are equivalent

 
PeelEggplant(au) // Can send an Aubergine to a Eggplant function, no probs

var testFunc func(Eggplant) 

testFunc = func(ep Eggplant) {} // Works, obviously
testFunc = func(ep Aubergine) {} // Gives the below error

var peeler EggplantPeeler
peeler = &AuberginePeeler{} // And the second error
}

func PeelEggplant(ep Eggplant) {
ep.Peel()
}

type EggplantPeeler interface {
Peel(Eggplant)
}

type AuberginePeeler struct{}

func (pw *AuberginePeeler) Peel(a Aubergine) {
a.Peel()
}

Gives two compiler errors: (not to mention the nil pointers if it were to run :-))

src/ift/main/interfaceThing.go:26: cannot use func literal (type func(Aubergine)) as type func(Eggplant) in assignment

src/ift/main/interfaceThing.go:29: cannot use AuberginePeeler literal (type *AuberginePeeler) as type EggplantPeeler in assignment:
*AuberginePeeler does not implement EggplantPeeler (wrong type for Peel method)
have Peel(Aubergine)
want Peel(Eggplant)
 
Thanks!

egon

unread,
Jun 25, 2014, 8:21:24 AM6/25/14
to golan...@googlegroups.com


On Wednesday, 25 June 2014 14:33:27 UTC+3, Damien Whitten wrote:
Hi Gophers,

I've got myself confused with Function Types. 
There are two exactly equivalent interfaces, and it seems a function which takes the first isn't able to be used to satisfy the function type of the second.


The interface types are not equivalent, although any type X that implements one interface will implement the other.

Also, use play.golang.org to give long examples. It makes experimenting with the code much easier.

+ egon


In this trivial example, I'd just use the same interface, but in the real example the interfaces are split into two packages.

Possible solutions:
- One 'master' package the other depends on
- One 'interfaces' package
- Functions which convert between the two 

So the questions I have: 
- Is there an 'easy way' - like a missing 'type assertion' or other language feature I am missing which would make this code work or?
- Is there a way to do something similar to this so those interfaces can exist in two packages which don't depend on each other? 
- And... would this make sense as a language feature?

package main

type Eggplant interface {
Peel()
}

type Aubergine interface {
Peel()
}

func main() {

var au Aubergine
var ep Eggplant

au = ep
ep = au // Just checking, they are equivalent

 
PeelEggplant(au) // Can send an Aubergine to a Eggplant function, no probs

var testFunc func(Eggplant) 

testFunc = func(ep Eggplant) {} // Works, obviously
testFunc = func(ep Aubergine) {} // Gives the below error

func(Eggplant) and func(Aubergine) have different types.

steve wang

unread,
Jun 25, 2014, 8:26:59 AM6/25/14
to golan...@googlegroups.com

egon

unread,
Jun 25, 2014, 8:27:19 AM6/25/14
to golan...@googlegroups.com


On Wednesday, 25 June 2014 15:21:24 UTC+3, egon wrote:


On Wednesday, 25 June 2014 14:33:27 UTC+3, Damien Whitten wrote:
Hi Gophers,

I've got myself confused with Function Types. 
There are two exactly equivalent interfaces, and it seems a function which takes the first isn't able to be used to satisfy the function type of the second.


The interface types are not equivalent, although any type X that implements one interface will implement the other.

Also, use play.golang.org to give long examples. It makes experimenting with the code much easier.

+ egon


In this trivial example, I'd just use the same interface, but in the real example the interfaces are split into two packages.


P.S. avoid facilitated examples, use the actual problem you are having and describe it in depth. Any suggestion based on facilitated/short examples can end up being a wrong solution. See this HowToAsk that explains why "facilitated" and "short descriptions" of a problem can get you in trouble.

Damien Whitten

unread,
Jun 25, 2014, 8:38:06 AM6/25/14
to golan...@googlegroups.com
Hi Egon,

Thanks for that link, that is exactly the thing I'm talking about.

I get that they are different types, what I'm looking for is *why* they are different types, and if there is an idiomatic way to 'tell the compiler' that they are the same, or arrange the code so that they work. (Without being a 'Why doesn't go have...' person, but maybe it's too late for that :-) )

My question is not about a specific thing which isn't working, it's just an 'oh, that's right, can't do that' which keeps coming up as I am writing, and looking for what others do instead.

So, more generally, how do you handle a package using an interface from another package without importing one from the other? Is there another solution than the ones I listed?

egon

unread,
Jun 25, 2014, 9:25:16 AM6/25/14
to golan...@googlegroups.com


On Wednesday, 25 June 2014 15:38:06 UTC+3, Damien Whitten wrote:
Hi Egon,

Thanks for that link, that is exactly the thing I'm talking about.

I get that they are different types, what I'm looking for is *why* they are different types,

Go has this explict rule that every type is distinct - it simplifies a lot of things. But there are also automatic conversions from one type to another, i.e. interface/struct/func type -> interface type.

This avoids a lot of problems that boils down to:

type Mm float64
type Inch float64

a := Mm(0.52)
b := Inch(0.62)
fmt.Println(a + b)

and if there is an idiomatic way to 'tell the compiler' that they are the same, or arrange the code so that they work. (Without being a 'Why doesn't go have...' person, but maybe it's too late for that :-) )

My rule of thumb is that if something is difficult in Go, it is probably a bad idea.

My question is not about a specific thing which isn't working, it's just an 'oh, that's right, can't do that' which keeps coming up as I am writing, and looking for what others do instead.

So, more generally, how do you handle a package using an interface from another package without importing one from the other? Is there another solution than the ones I listed?

I have hard time imagining the context where you need it. There are usually multiple solutions, and I try to avoid giving any specific suggestions until I have at least some context, otherwise you may take the first solution that works and run off with it, instead of trying to come up with a better solution.

Those 3 are the main ones; but remember the conversion between Aubergine -> Peeler is automatic, whereas func(Aubergine) -> func(Peeler) is not, so if you are not storing the function types, you can simply duplicate the interface.

Also, writing the conversion function for functions is ezpz. http://play.golang.org/p/NSHxxZMJYx

Of course there may be other solutions where you restructure the interfaces/implementers/package/etc. that solve the problem in a cleaner way... and avoid this conversion problem altogether. But for those suggestions I would need information about the context.

+ egon
Reply all
Reply to author
Forward
0 new messages