Why can't an interface type be a receiver

6,591 views
Skip to first unread message

honkskillet

unread,
Feb 2, 2015, 3:13:39 AM2/2/15
to golan...@googlegroups.com
Consider the following trivial program. (package main; import "fmt" implied)

type translatable interface{
spanishVersion() string
}

func (t translatable) printSpanish(){
fmt.Println(t.spanishVersion())
}

type helloW struct {}

func (helloW) spanishVersion() string{
return "Holla Mundo"
}

func main() {
var trans translatable
trans = helloW{}
trans.printSpanish()
}
This seems to me like it should logically work.  But it yields the following error.
prog.go:7: invalid receiver type translatable (translatable is an interface type)
prog.go:20: trans.printSpanish undefined (type translatable has no field or method printSpanish)
Is there any reason why an interface type can't be a receiver?  Maybe a philosophical reason in the design of Go?

thwd

unread,
Feb 2, 2015, 3:37:25 AM2/2/15
to golan...@googlegroups.com
It has to do with the concept of subtyping. If interface i0 is the broadest of n interfaces, where i(n) implements i(n-1) and some concrete type c implements i(n) then c also implements all of the other interfaces. This creates an "implements"-chain which if changed at any point between c and i0 will lead to broken code. So the same argument as the one against inheritance applies here.

Kornel Maczyński

unread,
Feb 2, 2015, 4:45:17 AM2/2/15
to golan...@googlegroups.com
Hi,
interface is just a description of behaviour (set of method signatures). The place for implementation is in the concrete types. Practice shows that interfaces (as they're now) are very useful and I guess adding implementation on top of them is an unnecessary complication (both semantically and implementation-wise).

It seems to me that the thing you are looking for is composition (or, alternatively, you can write a function that takes translatable as an argument and prints its Spanish version).

--
Kornel

Nico

unread,
Feb 2, 2015, 6:16:57 AM2/2/15
to golan...@googlegroups.com
I would say it's for "philosophical reasons".

A slightly more idiomatic version of your code would be:

https://play.golang.org/p/1XlR5qTcMr

package main

import "fmt"

type translatable interface {
spanishVersion() string
}

func printSpanish(t translatable) {
fmt.Println(t.spanishVersion())
}

type helloW struct{}

func (helloW) spanishVersion() string {
return "Hola Mundo"
}

func main() {
var trans translatable
trans = helloW{}
printSpanish(trans)
}

oju...@gmail.com

unread,
Feb 2, 2015, 7:55:30 AM2/2/15
to golan...@googlegroups.com
The code start to get smart when you combine interfaces.


Whenever you can, forget the actual types. Code for interfaces instead.

Ron Green

unread,
Apr 4, 2022, 1:27:46 PM4/4/22
to golang-nuts
in case anyone get's here and is confused...

you can wrap the additional functionality in the struct and use the interfaces from before

https://go.dev/play/p/e8aS0PZC6Zh

Simon Archer

unread,
Apr 4, 2022, 7:08:36 PM4/4/22
to golang-nuts
I think that playground is broken.

./prog.go:22:9: undefined: translatableImpl
./prog.go:27:11: undefined: translatableImpl

Go build failed.

I fixed it like this:
   https://go.dev/play/p/vZlwZIe9Ras

Sam Hughes

unread,
Apr 5, 2022, 2:45:11 AM4/5/22
to golang-nuts
So, for what it's worth: 

https://karthikkaranth.me/blog/functions-implementing-interfaces-in-go/

Otherwise, yeah. I'd love to be able to define interfaces with extra methods for implementors, but if you arrange your code around "traits", microstructs intended to present a possibly unergonomic API, intended to be implemented by the embedding struct. An example of this behavior working well is actually the io.Reader/io.Writer objects. It's not a terribly ergonomic API, but it can be incredibly flexible for implementations.
Reply all
Reply to author
Forward
0 new messages