interface as valid method receivers ?

206 views
Skip to first unread message

parais...@gmail.com

unread,
Oct 18, 2016, 2:12:17 PM10/18/16
to golang-nuts
Obviously in Go this is a compile time error :

type Foo interface {}


func
(f Foo) DoSomething(){}


I wonder if there is some technical limitations that make it undesirable or hard to implement, or it's just that Go designers didn't think it is a relevant feature.

I personally think there is it could be handy in some situations, instead of having to write a function without receiver, it could allow to attach behavior to interfaces automatically 
instead of the explicit :

func DoSomething(f Foo){}


what is your opinion on the matter ? Unfortunately I wasn't able to catch anyone of the Go team during the recent conference in Paris to ask that question.

Konstantin Khomoutov

unread,
Oct 18, 2016, 2:27:36 PM10/18/16
to parais...@gmail.com, golang-nuts
type Foo interface {
func DoSomething()
}

func (f Foo) DoSomething() {
}

var f Foo

f.DoSomething()

How do you propose to distinguish these two DoSomething()-s?

More to the point: how could anyone infer what's about to get called
from looking at that "f.DoSomething()" expression even if there could
be no conflict as in my contrived example -- is it a call on an
"interface itself" or on a concrete type an interface value contains?

xingtao zhao

unread,
Oct 18, 2016, 3:30:54 PM10/18/16
to golang-nuts, parais...@gmail.com
Why not make it a compiling time error? 

For example, for a struct: "type Foo has both field and method named DoSomething"
type Foo struct {
    DoSomething func()
}

func (f Foo) DoSomething() {
}


And for interface version:

type Foo interface { 
    func DoSomething() 


func (f Foo) DoSomething() { 


it is more straight forward: "Foo.DoSomething redeclared"

Viktor Kojouharov

unread,
Oct 19, 2016, 11:40:51 AM10/19/16
to golang-nuts, parais...@gmail.com

On Tuesday, October 18, 2016 at 9:27:36 PM UTC+3, Konstantin Khomoutov wrote:
On Tue, 18 Oct 2016 11:11:59 -0700 (PDT)
parais...@gmail.com wrote:

> Obviously in Go this is a compile time error :
>
> type Foo interface {}
>
>
> func (f Foo) DoSomething(){}
>  
> I wonder if there is some technical limitations that make it
> undesirable or hard to implement, or it's just that Go designers
> didn't think it is a relevant feature.
>
> I personally think there is it could be handy in some situations,
> instead of having to write a function without receiver, it could
> allow to attach behavior to interfaces automatically
> instead of the explicit :
>
> func DoSomething(f Foo){}
>
>
> what is your opinion on the matter ? Unfortunately I wasn't able to
> catch anyone of the Go team during the recent conference in Paris to
> ask that question.

  type Foo interface {
      func DoSomething()
  }

  func (f Foo) DoSomething() {
  }

  var f Foo

  f.DoSomething()

How do you propose to distinguish these two DoSomething()-s?

That's just a default method implementation. There's nothing inherently confusing about what gets called. If a concrete implementation exists, that gets called, otherwise the default one does.

Jan Mercl

unread,
Oct 19, 2016, 11:52:30 AM10/19/16
to Viktor Kojouharov, golang-nuts, parais...@gmail.com

On Wed, Oct 19, 2016 at 5:40 PM Viktor Kojouharov <vkojo...@gmail.com> wrote:

> That's just a default method implementation. There's nothing inherently confusing about what gets called. If a concrete implementation exists, that gets called, otherwise the default one does.

But to assign something to f (of type Foo) it must implement its method set, ie. it must have the DoSomething method. So by the above logic the default method can never get called.


--

-j

Konstantin Khomoutov

unread,
Oct 19, 2016, 11:55:00 AM10/19/16
to Viktor Kojouharov, golang-nuts, parais...@gmail.com
On Wed, 19 Oct 2016 08:40:51 -0700 (PDT)
Viktor Kojouharov <vkojo...@gmail.com> wrote:

[...]
> > type Foo interface {
> > func DoSomething()
> > }
> >
> > func (f Foo) DoSomething() {
> > }
> >
> > var f Foo
> >
> > f.DoSomething()
> >
> > How do you propose to distinguish these two DoSomething()-s?
>
> That's just a default method implementation. There's nothing
> inherently confusing about what gets called. If a concrete
> implementation exists, that gets called, otherwise the default one
> does.

But -- as I understood the original proposition -- these two methods
would serve two completely different purposes: one operates on
interface types; another one is doing something with a value of a
concrete type implementing that interface. Am I not correct?
If I'm correct that would be very confusing.

Jakob Borg

unread,
Oct 19, 2016, 11:55:18 AM10/19/16
to Viktor Kojouharov, golang-nuts, parais...@gmail.com
The one way this could be possibly useful, in my opinion, would be to add methods to existing interfaces (from other packages no less), a la extensions in Objective-C (and Swift). So say

extending io.Reader {
  ReadAll() ([]byte, error)
}

func (r io.Reader) ReadAll() ([]byte, error) {
  // implementation than can use io.Reader methods on r but nothing else
}

and any type implementing io.Reader now has a ReadAll() method as well. However, this is spooky action at a distance as it would be very unclear att the call site where this ReadAll() might be defined... I could imagine declaring it as a new interface:

interface ReadAller: io.Reader {
  ReadAll() ([]byte, error)
}

func (r ReadAller) ReadAll() ([]byte, error) {
  // implementation
}

Go now has inheritance! Of interfaces, at least... But then the caller needs to cast the io.Reader to a ReadAller to use the method, which is no more convenient than just calling the ioutil.ReadAll function to begin with, and we have muddled the language for no reason.

So all in all, lets not. :)

//jb


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Viktor Kojouharov

unread,
Oct 19, 2016, 2:57:46 PM10/19/16
to golang-nuts, vkojo...@gmail.com, parais...@gmail.com
Not really, as this is all hypothetical, it might be implemented in a way so that any type that wants to satisfy an interface with default methods has to at least implement all non-default ones. That is to say, with the above example interface, any and all types will be able to match, since the interface doesn't define any other methods (in a sense, it turns into interface{}). However, if a type wishes to define any method that has a default implementation, it can do so, and that implementation will be used.
 
 

--

-j

Jan Mercl

unread,
Oct 19, 2016, 3:16:50 PM10/19/16
to Viktor Kojouharov, golang-nuts, parais...@gmail.com
On Wed, Oct 19, 2016 at 8:58 PM Viktor Kojouharov <vkojo...@gmail.com> wrote:

> Not really, as this is all hypothetical, it might be implemented in a way so that any type that wants to satisfy an interface with default methods has to at least implement all non-default ones. That is to say, with the above example interface, any and all types will be able to match, since the interface doesn't define any other methods (in a sense, it turns into interface{}). However, if a type wishes to define any method that has a default implementation, it can do so, and that implementation will be used.

This can serve as a good answer to the question in the thread title. I mean, hypothetically allowing interface types as method receivers makes things less intuitive to use, more complex to specify, implement and understand to source code reader.

--

-j

Viktor Kojouharov

unread,
Oct 19, 2016, 3:35:33 PM10/19/16
to golang-nuts, vkojo...@gmail.com, parais...@gmail.com
I disagree. I see no evidence nor reason why such a feature would make things less intuitive or more complex. On the contrary, handling a feature in this way seems quite intuitive.
 

--

-j

xingtao zhao

unread,
Oct 19, 2016, 5:30:53 PM10/19/16
to golang-nuts, vkojo...@gmail.com, parais...@gmail.com
I think the original proposition is not to add default implementation for the methods in an interface. The proposal was just want to add extra methods to the interface. These methods will not get into the vtable of the interface. Yes, this can be implemented by package level function, but it is not as nature as adding methods directly to the interface.

parais...@gmail.com

unread,
Oct 21, 2016, 2:59:10 PM10/21/16
to golang-nuts, parais...@gmail.com
Hey folks, what a great discussion.

To be clear, if something like that would exist, it should have obvious limitation, like any Go features regarding structs and interfaces.

It would be illegal to do that for instance :

type Foo interface {
   
Do()
}
func
(f Foo)interface Do(){}

Now I don't think it would make code harder to read. If Foo is used as an argument :

func AcceptFoo(f Foo){
   f
.Do() // Execute Foo.Do
}
If Do is not inside the Foo "contract" but a method of Foo, there is ambiguity as to what is called.

Even if a struct implementing Foo has a Do function of his own, AcceptFoo cannot know that
since it is not defined on the interface .

When it comes to methods on structs, nothing would change :

type
Bar struct {}
func
(b Bar)Do()

bar := Bar{}

bar
.Do() // execute Bar.Do()

// however

var bar2 Foo = Bar{}

bar2
.Do() // execute Foo.Do()


A strict behavior should be defined one way or another, but I think this one would be interesting.

Anyway It was just a thought on the matter, no big deal. It would be a great way to encapsulate some behavior without exposing internals or using package level functions accepting interfaces thus leading to cleaner API for libraries. If you think about technical implications or some current Go features this idea might break, let me know.

parais...@gmail.com

unread,
Oct 21, 2016, 3:13:30 PM10/21/16
to golang-nuts, parais...@gmail.com
> there is ambiguity as to what is called.

Sorry I meant there NO ambiguity as to what is called.


Le mardi 18 octobre 2016 20:12:17 UTC+2, parais...@gmail.com a écrit :
Reply all
Reply to author
Forward
0 new messages