duplicate method in interface

1,393 views
Skip to first unread message

r2p2

unread,
Mar 10, 2012, 9:19:43 AM3/10/12
to golan...@googlegroups.com

Jan Mercl

unread,
Mar 10, 2012, 9:44:55 AM3/10/12
to golan...@googlegroups.com


On Saturday, March 10, 2012 3:19:43 PM UTC+1, r2p2 wrote:

I don't see the problem. The interface should just look if such a function exists. And if it exists then the object has such an interface. Where is the problem in joining multiple interfaces if the containing functions do the same stuff?

From a quick peek at the code I think the 'inOutMessage' really has duplicate methods 'Type() byte' and so the compiler is just right.

r2p2

unread,
Mar 10, 2012, 9:55:51 AM3/10/12
to golan...@googlegroups.com
But why is that a problem. The interface is for duck typing which means that this is more like a pattern matching. If a has a pattern already he should ignore the duplicate.

Jan Mercl

unread,
Mar 10, 2012, 10:01:26 AM3/10/12
to golan...@googlegroups.com
On Saturday, March 10, 2012 3:55:51 PM UTC+1, r2p2 wrote:
But why is that a problem. The interface is for duck typing which means that this is more like a pattern matching. If a has a pattern already he should ignore the duplicate.

I probably don't understand. If an interface declares two identical methods how it could *not* be a problem?

r2p2

unread,
Mar 10, 2012, 10:08:39 AM3/10/12
to golan...@googlegroups.com
Why does the interface declares two identical methods. I would see this as an: If you (struct) want to have this interface, you have to implement these methods. Well if there are two he has to ignore one.

Is there another solution? I have input and output messages and I don't want to implement read for output messages and write for input messages. Both have a type attribute.

Jan Mercl

unread,
Mar 10, 2012, 10:21:18 AM3/10/12
to golan...@googlegroups.com
On Saturday, March 10, 2012 4:08:39 PM UTC+1, r2p2 wrote:
Why does the interface declares two identical methods.

Well, you have explicitly declared the duplicity. I'm lost ;-)

> I would see this as an: If you (struct) want to have this interface, you have to
> implement these methods. Well if there are two he has to ignore one.

I've no idea how this is meant. There is no way know to me how an interface can have duplicate methods (what would be the semantics???), so what 'ignore one of the duplicates' means???


Is there another solution?

Sure. Design your interface w/o duplicate methods. I don't mean it in any bad way, it's the only option available ;-)

r2p2

unread,
Mar 10, 2012, 10:31:13 AM3/10/12
to golan...@googlegroups.com
How do I inline my answer in Google Groups?

Do I see this right that you don't know my code to get this error message? In my first post is a link to golang playground which contains this code. In case the link was filtered: There it is

type hasType interface {
    Type() byte
}

type incomingMessage interface {
    hasType
    ReadFrom(w io.Reader) error
}

type outgoingMessage interface {
    hasType
    WriteTo(w io.Writer) error
}

type inOutMessage interface {
    incomingMessage
    outgoingMessage
}

Am Samstag, 10. März 2012 16:21:18 UTC+1 schrieb Jan Mercl:
On Saturday, March 10, 2012 4:08:39 PM UTC+1, r2p2 wrote:
Why does the interface declares two identical methods.

Well, you have explicitly declared the duplicity. I'm lost ;-)

> I would see this as an: If you (struct) want to have this interface, you have to
> implement these methods. Well if there are two he has to ignore one.

I've no idea how this is meant. There is no way know to me how an interface can have duplicate methods (what would be the semantics???), so what 'ignore one of the duplicates' means??

Is there another solution?

Sure. Design your interface w/o duplicate methods. I don't mean it in any bad way, it's the only option available ;-)

Jan Mercl

unread,
Mar 10, 2012, 10:42:51 AM3/10/12
to golan...@googlegroups.com
On Saturday, March 10, 2012 4:31:13 PM UTC+1, r2p2 wrote:
Do I see this right that you don't know my code to get this error message? In my first post is a link to golang playground which contains this code. In case the link was filtered: There it is

The code is possible to see from the OP, no problem.
 

type hasType interface {
    Type() byte
}

type incomingMessage interface {
    hasType
    ReadFrom(w io.Reader) error 
}

The method set of 'incomingMessage' is: { Type() byte; ReadFrom(w io.Reader) error }
 

type outgoingMessage interface {
    hasType
    WriteTo(w io.Writer) error
}

The method set of 'outgoingMessage' is: { Type() byte; WriteTo(w io.Writer) error }
 

type inOutMessage interface {
    incomingMessage
    outgoingMessage
}

The method set of 'inOutMessage' is: { Type() byte; ReadFrom(w io.Reader) error; Type() byte; WriteTo(w io.Writer) error }

The Type method is declared twice in 'inOutMessage'. That's not possible. This code cannot be accepted by the compiler. You must redesign your code to not have duplicate methods in any of its interfaces. No other way exists, sorry.

Benny Siegert

unread,
Mar 10, 2012, 11:36:56 AM3/10/12
to r2p2, golan...@googlegroups.com
There is an easy solution to your problem: Remove hasType from
incomingMessage and outgoingMessage. You can always check at runtime
with a type assertion (to hasType) if something has a type method.

--Benny.

Ugorji Nwoke

unread,
Mar 10, 2012, 11:45:40 AM3/10/12
to golan...@googlegroups.com
Yes, but the OP is asking a valid question IMO. He/She knows that a solution is to restructure his code. But the question is, "Given that the function signatures are the same, why does the compiler barf?" The method set of 'inOutMessage' interface should be: { Type() byte; ReadFrom(w io.Reader) error; WriteTo(w io.Writer) error }. 

I think that's a valid question for the Go team. 

Harry de Boer

unread,
Mar 10, 2012, 11:47:05 AM3/10/12
to golan...@googlegroups.com
Iam not exactly sure why it is not allowed, but I guess it is because the compiler sees it as an ambiguity: it does not know whether to pick incomingMessage.Type() or outgoingMessage.Type(). As far as I know go does not do pattern matching but type matching and these might be seen as different types, but it is a guess.

Anyway I think it is more clear to do it like below, and that does exactly what you want:

type incomingMessage interface {

    Type() byte
    ReadFrom(w io.Reader) error
}

type outgoingMessage interface {
    Type() byte
    WriteTo(w io.Writer) error
}

type inOutMessage interface {
    Type() byte
    ReadFrom(w io.Reader) error
    WriteTo(w io.Writer) error
}

On Saturday, March 10, 2012 3:55:51 PM UTC+1, r2p2 wrote:

r2p2

unread,
Mar 10, 2012, 3:41:57 PM3/10/12
to golan...@googlegroups.com
Thank you. My (he) first intention was a solution. The second one is to ask if this should be possible.

Guillaume Lescure

unread,
Mar 10, 2012, 4:15:47 PM3/10/12
to golan...@googlegroups.com
I agree with you r2p2, it's should work according to the duck typing philosophy. I think it's a bug.

Steven Blenkinsop

unread,
Mar 10, 2012, 5:12:32 PM3/10/12
to Guillaume Lescure, golan...@googlegroups.com
On 2012-03-10, at 4:15 PM, Guillaume Lescure <guil.l...@gmail.com> wrote:

> I agree with you r2p2, it's should work according to the duck typing philosophy. I think it's a bug.

It is not a bug, it is working as intended and specified. Interfaces aren't defined based on some "duck typing philosophy", they are defined as the language authors saw fit.

The problem with just ignoring duplicates is that the methods may actually come from different places and mean different things (though the serendipity of this seems unlikely). An implementer may then not know which spec to follow. If this situation arises, the person defining the interface should make their intent explicit in the code.

Plausibly, the language could recognize that the method names originate in the same method spec and allow it. I think that would make sense and help in this case.

r2p2

unread,
Mar 10, 2012, 6:08:34 PM3/10/12
to golan...@googlegroups.com, Guillaume Lescure
The only relation between an interface an an struct is a method name, the parameter an the return value. You only need one interface and one method to use a struct with a method as an interface which does things not intended by the author of the interface.

Another thing is that the interfaces incomingMessages and outgoingMessage pointing to *one* interface which contains the duplicate method. So we have the same intention for two functions because they where included from the same interface.

Ugorji Nwoke

unread,
Mar 10, 2012, 7:36:27 PM3/10/12
to golan...@googlegroups.com, Guillaume Lescure
For embedded/anonymous fields, duplicate methods may cause concerns. However, for embedded interfaces, duplicate method definitions seem to cause concerns if/only if the method signatures are different (eg method abc() error and method abc() int), since an interface only defines signatures of method sets, not their implementation.

Now, the Go authors may be conservative and just restrict this use-case. And that's  fair. But I think it's still a fair question to ask.

Jim Teeuwen

unread,
Mar 11, 2012, 7:40:31 AM3/11/12
to golan...@googlegroups.com

I think that's a valid question for the Go team.

I have to concur. For interfaces it should not matter which version of a signature the compiler 'picks'. It's just a signature, not an implementation choice. One of them should therefor simply be ignored.

Unless I am missing some hidden rationale, this seems like a bug.

chris dollin

unread,
Mar 11, 2012, 8:05:36 AM3/11/12
to Jim Teeuwen, golan...@googlegroups.com

This

interface { MyMethod() MyType; MyMethod() MyType }

is pretty clearly a mistake (even if you have a semantics which
just drops duplicates, as the term `set` would imply).

If you want to catch this, BUT allow other routes to duplication,
you're going to have non-trivial rules to decide what counts as
a problem or not.

I can easily see that Go team deciding that such rules were
not Simple and would mean more time spent maintaining
the spec and compilers and handling questions on the list.

Chris

--
Chris "allusive" Dollin

Steven Blenkinsop

unread,
Mar 11, 2012, 1:16:05 PM3/11/12
to Jim Teeuwen, golan...@googlegroups.com
On Sunday, March 11, 2012, Jim Teeuwen <jimte...@gmail.com> wrote:
>
>> I think that's a valid question for the Go team.
>
> I have to concur. For interfaces it should not matter which version of a signature the compiler 'picks'. It's just a signature, not an implementation choice. One of them should therefor simply be ignored.

type Artist interface {
   // Draw an image
   Draw()

   // Erase the image
   Erase()
}

type Cowboy interface {
   // Draw weapon
   Draw()

  // Fire weapon
   Fire()
}

type ArtisticCowboy interface { Artist; Cowboy }

A method is a mix of signature and intent. If there's any incompatibility in the intent behind the methods (it could be much more subtle than this, like behaviour at a boundary condition) it will make the interface impossible to implement correctly.


> Unless I am missing some hidden rationale, this seems like a bug.

Anything deliberate is never a bug, even if you don't understand the rationale.

r2p2

unread,
Mar 11, 2012, 2:04:49 PM3/11/12
to golan...@googlegroups.com, Jim Teeuwen
But you need only one interface, and one struct to create such an incompatibility.

type Cowboy interface {
   // Draw weapon
   draw()
}

type Cube struct {
}

func (c *Cube) draw() {
  // draw an image
}

func do_something(c Cowboy) {
  c.draw()
}

Cube is not realy a cowboy but you can pass it to do_something. You have to be sure that you use an interface like intended but the language doesn't force you.

If we ignore this for a second and try to believe that one interface has an intention, than this intention should not change if the interface stays the same. If both interfaces Cowboy and Artist would include one interface (eg. Drawable) the intention of draw() should stay the same. So the compiler could allow this because Artist and Cowboy use the draw with the same intention. If not they could include different interfaces (eg Drawable and DrawableWeapon [both would contain the draw method]).

Steven Blenkinsop

unread,
Mar 11, 2012, 3:20:12 PM3/11/12
to r2p2, golan...@googlegroups.com, Jim Teeuwen
On Sun, Mar 11, 2012 at 2:04 PM, r2p2 <robert...@gmx.net> wrote:
But you need only one interface, and one struct to create such an incompatibility.
<snip>
Cube is not realy a cowboy but you can pass it to do_something. You have to be sure that you use an interface like intended but the language doesn't force you.

The problem isn't incompatibility, it's impossibility. While the Circle is not a Cowboy (since it breaks some contract not evident in the signature but inherent to the Cowboy interface), it is still possible to make types that properly implement Cowboy. It's up to the programmer to know that the Circle doesn't meet the Cowboy contract as there is no way for the compiler to catch it.

In the case I presented, the interface is impossible to implement correctly. Luckily, the compiler rejects this case. Also, if one of the methods changes its signature for some reason, then the difference definitely is unresolvable, and this kind of tenuous correlation is something that should be avoided.
 
If we ignore this for a second and try to believe that one interface has an intention, than this intention should not change if the interface stays the same. If both interfaces Cowboy and Artist would include one interface (eg. Drawable) the intention of draw() should stay the same. So the compiler could allow this because Artist and Cowboy use the draw with the same intention. If not they could include different interfaces (eg Drawable and DrawableWeapon [both would contain the draw method]).

Which is why I said it would be reasonable to define duplicate methods as having the same name, but originating in different method specs (until someone proves me wrong ;)), thereby allowing the case where you know there aren't any incompatibilities. Whether it's worthwhile, though, is another thing. It seems to come up infrequently enough, and can be resolved easily enough, that such a rule isn't really necessary.

Florian Weimer

unread,
Mar 11, 2012, 4:35:27 PM3/11/12
to golan...@googlegroups.com
* Guillaume Lescure:

> I agree with you r2p2, it's should work according to the duck typing
> philosophy. I think it's a bug.

In general, checking for conflicts in interface type definitions is a
good idea because there might be an unintended ambiguity. But given
that the method comes from the same declared interface type, the error
is indeed rather pointless here. On the other hand, the error is
suppressed in such cases, the rules for a valid interface definition
become pretty involved. So it seems to me that there isn't a
compelling case to change the compiler, after all.

Johann Höchtl

unread,
Mar 12, 2012, 2:40:45 PM3/12/12
to golan...@googlegroups.com

May we ask the language designers for clarification on this possible issue?

- Joann

Ian Lance Taylor

unread,
Mar 12, 2012, 2:59:55 PM3/12/12
to Johann Höchtl, golan...@googlegroups.com
Johann Höchtl <johann....@gmail.com> writes:

> May we ask the language designers for clarification on this possible issue?

Speaking purely personally, the current spec is quite simple. And I
don't think we should permit

interface {
func F()
func F()
}

So the question is: do we get an advantage by complicating the spec to
support this case. And my personal answer is that this is an unusual
edge case, and it's not worth it.

Ian

Steven Blenkinsop

unread,
Mar 12, 2012, 6:42:21 PM3/12/12
to Ian Lance Taylor, Johann Höchtl, golan...@googlegroups.com
On 2012-03-12, at 2:59 PM, Ian Lance Taylor <ia...@google.com> wrote:

Johann Höchtl <johann....@gmail.com> writes:

Speaking purely personally, the current spec is quite simple.  And I
don't think we should permit

interface {
   func F()
   func F()
}

So the question is: do we get an advantage by complicating the spec to
support this case.  And my personal answer is that this is an unusual
edge case, and it's not worth it.

Ian

I thought that would probably be the case. Just to be clear, I think the change to the spec in question would be to change the last sentence of the first paragraph of the section on method sets to:

In a type's method set, each method must have a unique method name, unless the type is an interface and the duplicate method names originate in the same method spec.

I don't know what impact this would have on implementation, but it is a bit of a rare and nonessential edge case.


Speaking of which, there's still an inaccuracy in the spec (as I see it). Where it says:

Two named types are identical if their type names originate in the same type declaration.

I think it should say:

Two named types are identical if their type names originate in the same type spec.

It's a subtle distinction, but it's what makes foo and bar in `type (foo int; bar int)` different.

楚杰

unread,
Mar 12, 2012, 9:22:13 PM3/12/12
to golan...@googlegroups.com, Johann Höchtl
I think what they want is "diamond multi-inheritance" for interfaces. Is that correct?

在 2012年3月13日星期二UTC+8上午2时59分55秒,Ian Lance Taylor写道:

Steven Blenkinsop

unread,
Mar 12, 2012, 10:59:52 PM3/12/12
to 楚杰, golan...@googlegroups.com, Johann Höchtl
On Mar 12, 2012, at 9:22 PM, 楚杰 <gla...@gmail.com> wrote:

I think what they want is "diamond multi-inheritance" for interfaces. Is that correct?

Yes and no. Interfaces don't contain implementation, and their composition is flat – they don't actually contain a copy of the interfaces they're composed from – so you don't get anything resembling the diamond inheritance problem. However, if you traced the origins of the problem methods, it would form a diamond shape, and the issue is that the compiler is treating the methods as [conflicting] duplicates even though they are identical.

eik...@eikeon.com

unread,
Apr 30, 2012, 3:30:29 PM4/30/12
to golan...@googlegroups.com
I have a similar use case and just hit the same issue. Is this issue being tracked yet in the golang issue tracker, or still being hashed out here in this thread?

Kyle Lemons

unread,
Apr 30, 2012, 4:08:50 PM4/30/12
to eik...@eikeon.com, golan...@googlegroups.com
On Mon, Apr 30, 2012 at 12:30 PM, <eik...@eikeon.com> wrote:
I have a similar use case and just hit the same issue. Is this issue being tracked yet in the golang issue tracker, or still being hashed out here in this thread?

I think the consensus was that it's working as intended.

Daniel Krech

unread,
Apr 30, 2012, 4:18:59 PM4/30/12
to Kyle Lemons, golan...@googlegroups.com

On Apr 30, 2012, at 4:08 PM, Kyle Lemons wrote:

On Mon, Apr 30, 2012 at 12:30 PM, <eik...@eikeon.com> wrote:
I have a similar use case and just hit the same issue. Is this issue being tracked yet in the golang issue tracker, or still being hashed out here in this thread?

I think the consensus was that it's working as intended.

Thank you for the response. I think my use case is turning out better the way things are working now anyway.

Thanks again.

roger peppe

unread,
May 1, 2012, 3:57:53 AM5/1/12
to Steven Blenkinsop, 楚杰, golan...@googlegroups.com, Johann Höchtl
[i've just realised i wrote this message weeks ago but
never sent it. sending for the record]

I've encountered this issue in the past, and the conclusion I came
to is: never nest interface definitions more than two deep.

also, if you're nesting interface definitions and exporting the
resulting interface type, it's best to have an interface type
that doesn't mix embedding and methods.

so this is good:

type Aer interface {
A()
}

type Ber interface {
B()
}

type ABer interface {
Aer
Ber
}


but this is not:

type Aer interface {
A()
}

type ABer interface {
Aer
B()
}

this is because it's not uncommon to want
to refer to the added methods themselves, without
the methods from the embedded type.

if you're not exporting the type, then it doesn't matter so much.

applying the above principles to the original problem
gives something like this:


type message interface {
Type() byte
}

type readerFrom interface {
ReadFrom(w io.Reader) error
}

type writerTo interface {
WriteTo(w io.Writer) error
}

type inOutMessage interface {
message
readerFrom
writerTo
}

Ugorji Nwoke

unread,
Jun 1, 2012, 8:42:56 AM6/1/12
to golan...@googlegroups.com, Ian Lance Taylor, Johann Höchtl
I just came across a need for this again and wanted to share what I had to do.

I have code that implements returns implementations of rpc.ClientCodec and rpc.ServerCodec, but don't want to export the underlying types. So I had:

type RPCCodec interface {
  rpc.ClientCodec
  rpc.ServerCodec
}

func NewSimpleRPCCodec(...) RPCCodec { ... }
func NewCustomRPCCodec(...) RPCCodec { ... }
// ...

Unfortunately, both rpc.ClientCodec and rpc.ServerCodec implement Close() error method. So I had to do instead:

type RPCCodec interface {
  // write out all ClientCodec methods, because both have Close() meaning they both cannot be embedded
  WriteRequest(*rpc.Request, interface{}) error
  ReadResponseHeader(*rpc.Response) error
  ReadResponseBody(interface{}) error
  // rpc.ClientCodec
  rpc.ServerCodec
}

I understand and am partial to Steven's explanation regarding "intent", but just wanted to throw this data point out there in case the core Go team was still thinking about this.

Jan Mercl

unread,
Jun 1, 2012, 9:08:18 AM6/1/12
to Ugorji Nwoke, golan...@googlegroups.com
On Fri, Jun 1, 2012 at 2:42 PM, Ugorji Nwoke <ugo...@gmail.com> wrote:
I just came across a need for this again and wanted to share what I had to do.

I have code that implements returns implementations of rpc.ClientCodec and rpc.ServerCodec, but don't want to export the underlying types. So I had:

type RPCCodec interface {
  rpc.ClientCodec
  rpc.ServerCodec
}

func NewSimpleRPCCodec(...) RPCCodec { ... }
func NewCustomRPCCodec(...) RPCCodec { ... }
// ...

Unfortunately, both rpc.ClientCodec and rpc.ServerCodec implement Close() error method. So I had to do instead:

type RPCCodec interface {
  // write out all ClientCodec methods, because both have Close() meaning they both cannot be embedded
  WriteRequest(*rpc.Request, interface{}) error
  ReadResponseHeader(*rpc.Response) error
  ReadResponseBody(interface{}) error
  // rpc.ClientCodec
  rpc.ServerCodec
}

What about:

package main

import (
        "net/rpc"
)

type RPCCodec struct {
        Client rpc.ClientCodec
        Server rpc.ServerCodec
}

func NeweRPCCodec(c rpc.ClientCodec, s rpc.ServerCodec) *RPCCodec {
        return &RPCCodec{c, s}
}

func (c *RPCCodec) foo() {
        c.Client.Close()
        c.Server.Close()
}

func bar(c *RPCCodec) {
        c.Client.Close()
        c.Server.Close()
}

func main() {
}

-j

Ugorji Nwoke

unread,
Jun 1, 2012, 9:19:27 AM6/1/12
to golan...@googlegroups.com, Ugorji Nwoke
This wouldn't really work for my use case. For my use case, there was enough shared code between client and server side codec, that it made sense to just have one struct implement both sides. My issue was trying to convey that an unexported type implements both interfaces.

Without having the "combo interface", I could do:
   func NewSimpleRPCCodec(...) *simpleRpcCodec { ... }
   func NewCustomRPCCodec(...) *customRpcCodec { ... }
and document that return value (though unexported) implements both rpc.ClientCodec and rpc.ServerCodec.
However, the docs start looking ugly and leaking unexported types.

Eventually, I actually went ahead and wrote NewXXXRPCClientCodec(...) rpc.ClientCodec and NewXXXRPCServerCodec(...) rpc.ServerCodec functions, which are basically copies of each other.

But I think this use may show why duplicate methods may pose a challenge even when working with the core library.

Reply all
Reply to author
Forward
0 new messages