Why can't single-method interfaces not be implemented by embedding?

227 views
Skip to first unread message

cpu...@gmail.com

unread,
Feb 27, 2025, 12:06:59 PMFeb 27
to golang-nuts
About every single time I feel like I understand Go interfaces I'm being taught differently.

Consider this play: https://play.golang.com/p/qeF4KvaPcwp

There are 2 single method interfaces. One where interface and method names are equal, one where they are different.

I would have expected m to implement both interfaces, but it doesn't. Why is that?

Thanks,
Andi

Ian Cottrell

unread,
Feb 27, 2025, 12:27:18 PMFeb 27
to cpu...@gmail.com, golang-nuts
It's because your method and field have the same name, if you rename the interface to SameNamer (and thus rename the field as well) it will work.

--
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.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/22aaa13f-41d9-4d4c-93c8-455faaef50c2n%40googlegroups.com.

burak serdar

unread,
Feb 27, 2025, 12:28:16 PMFeb 27
to cpu...@gmail.com, golang-nuts
The embedded name `EqualName` shahows the method called `EqualName`.

Rename the `EqualName` interface to `EqualNamer`, and things work.

cpu...@gmail.com

unread,
Feb 27, 2025, 12:32:05 PMFeb 27
to golang-nuts
I can see that that's the difference and cause but I'm not convinced by the explanation (although that clearly is what happens):

If the embedded method name EqualName shadows the method name EqualName that should still implement the interface of the same signature? I.e. why doesn't the shadow implement the interface?

Ian Lance Taylor

unread,
Feb 27, 2025, 12:40:30 PMFeb 27
to cpu...@gmail.com, golang-nuts
On Thu, Feb 27, 2025 at 9:32 AM cpu...@gmail.com <cpu...@gmail.com> wrote:
>
> I can see that that's the difference and cause but I'm not convinced by the explanation (although that clearly is what happens):
>
> If the embedded method name EqualName shadows the method name EqualName that should still implement the interface of the same signature? I.e. why doesn't the shadow implement the interface?

I'm sorry, I don't understand the question. I'll try to explain what
is happening.

m.EqualName has to mean something. The Go language defines it as
meaning the field in m's type, rather than the embedded method.
Therefore, the type meter does not have a method EqualName. Therefore,
the type meter does not implement the EqualName interface.

I note that this kind of confusion between interface name and method
name is the Go standard library is careful to do things like an
interface Writer with a method Write. We don't use the same name for
an interface type and the method(s) that it includes.

Ian

cpu...@gmail.com

unread,
Feb 27, 2025, 12:49:25 PMFeb 27
to golang-nuts
Thanks Ian, you are of course correct- but I still don't get it. Thank you for taking the time.

> m.EqualName has to mean something. The Go language defines it as
meaning the field in m's type, rather than the embedded method.

Doesn't have meter an embedded field of type EqualName (the interface)?

> Therefore, the type meter does not have a method EqualName. Therefore,
the type meter does not implement the EqualName interface.

meter doesn't. But impl's methods get promoted to meter- which happens with different name: clearly the different name method has become promoted, implements the different namer interface and is non-nil.

I still don't fully understand why this doesn't work for equal name. If impl's equal name method does get promoted it should implement the interface since meter now as a equal name method. If it doesn't (due to name conflict with the embedded equal name interface) where would still be the embedded equal name interface (which might be nil but still existing)?

Thanks,
Andi

Ian Lance Taylor

unread,
Feb 27, 2025, 4:46:06 PMFeb 27
to cpu...@gmail.com, golang-nuts
On Thu, Feb 27, 2025 at 9:49 AM cpu...@gmail.com <cpu...@gmail.com> wrote:
>
> Thanks Ian, you are of course correct- but I still don't get it. Thank you for taking the time.
>
> > m.EqualName has to mean something. The Go language defines it as
> meaning the field in m's type, rather than the embedded method.
>
> Doesn't have meter an embedded field of type EqualName (the interface)?

It has an embedded field whose name is EqualName and whose type is
EqualName. It's though the code said

type meter struct {
EqualName EqualName
DifferentNamer DifferentNamer
}

except that methods and fields of the embedded types are promoted.


> > Therefore, the type meter does not have a method EqualName. Therefore,
> the type meter does not implement the EqualName interface.
>
> meter doesn't. But impl's methods get promoted to meter- which happens with different name: clearly the different name method has become promoted, implements the different namer interface and is non-nil.
>
> I still don't fully understand why this doesn't work for equal name. If impl's equal name method does get promoted it should implement the interface since meter now as a equal name method. If it doesn't (due to name conflict with the embedded equal name interface) where would still be the embedded equal name interface (which might be nil but still existing)?

As you say, if the EqualName method were promoted it would conflict
with the existing field of type EqualName. Therefore, it is not
promoted. Therefore, meter does not have a method named EqualName. It
has a field named EqualName instead. Therefore, meter does not
implement the interface EqualName. It doesn't have a method EqualName,
so there is no way that it could implement the interface EqualName.

Ian

Axel Wagner

unread,
Feb 27, 2025, 4:55:58 PMFeb 27
to Ian Lance Taylor, cpu...@gmail.com, golang-nuts
Just to quote the spec to clarify, perhaps:

> A field or method f of an embedded field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f

So there are two conditions for a method to be promoted: 1. it must be a legal selector (this is given for the example) and 2. that selector must denote the method.

To check whether the selector `m.EqualName` (if `m` has type `meter` or `*meter`) denotes this field or method, we look up the rules for selector expressions (emphasis mine):

> For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.

The field `meter.EqualName` has a more shallow depth than `meter.EqualName.EqualName`, thus `m.EqualName` denotes the field, not the method.
Thus, the method is not promoted. Thus `meter` has no `EqualName` method, as the only way it could get one is by promotion.
 

--
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.

cpu...@gmail.com

unread,
Feb 28, 2025, 10:51:32 AMFeb 28
to golang-nuts
Thank you Axel for quoting the spec.

On Thursday, February 27, 2025 at 10:55:58 PM UTC+1 Axel Wagner wrote:
> For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.

The field `meter.EqualName` has a more shallow depth than `meter.EqualName.EqualName`, thus `m.EqualName` denotes the field, not the method.
Thus, the method is not promoted. Thus `meter` has no `EqualName` method, as the only way it could get one is by promotion.

I can see why the EqualName method is not promoted. However, there is still the EqualName field. Even if it's not useful (since zero value) I would expect this fields to make meter implement the EqualName interface. See https://play.golang.com/p/awtbP1X93Pg for an example that shows that presence of an interface field is enough.

Thanks,
Andi

Axel Wagner

unread,
Feb 28, 2025, 11:16:17 AMFeb 28
to cpu...@gmail.com, golang-nuts
The two situations are not the same. Again, the salient question is "what is the shallowest depth b, that a.b could refer to?". That is what `a.b` means. And a method `b` is promoted to `a`, if `a.b` refers to a method.
In this new example, `new(s).Foo` refers to the shallowest depth method or field `Foo`, which is `s.iface.Foo`, which is a method, so it is promoted.
If `s` also had a field `Foo`, then `new(s).Foo` would refer to that field (as it is is at a shallower depth) and there is no method: https://play.golang.com/p/OFYNiB98qyJ
That's your original example: `m.EqualName` refers to `meter.EqualName`, not `meter.EqualName.EqualName`. So it refers to a field, not a method, so no method is promoted.

The spec is really clear on this regard. First you decide what the selector refers to. And that decides whether a method is promoted. Full stop.

If you want to make an argument that `meter` should have a method `EqualName` you need to actually say where it is coming from. Given that you do not declare a method `func (meter) EqualName`, it could only get that method via promotion. But the definition of promotion of methods clearly says that no promotion is happening.
 

Thanks,
Andi

--
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.

Axel Wagner

unread,
Feb 28, 2025, 11:24:39 AMFeb 28
to cpu...@gmail.com, golang-nuts
To clarify: When I say "make an argument" I mean "from the spec".

What I'm trying to explain is why the behaviour you show is in accordance with the spec.
What Ian is trying to explain is additionally, why the spec says what it says (i.e. arguing why the specified behaviour is sensible).

It would be helpful to know, which of these you are talking about.
Do you disagree that the behaviour you show is in accordance with the spec? In that case, it would be helpful to have an argument based on the spec, not by analogy with other programs. That is, find a section of the spec that says the program should behave differently.
Or are you arguing that the behaviour is confusing and the spec should be changed? That's a fair thing to ask and in that case, it obviously makes no sense to talk about what the spec says and I would yield back to Ian.

tapi...@gmail.com

unread,
Feb 28, 2025, 1:07:32 PMFeb 28
to golang-nuts

The full form of the EqualName field is meter.EqualName,
the full form of the EqualName method is mete.EqualName.EqualName.

The longer one is shadowed by the shorter one.

func main() {
impl := new(impl)

var m = &meter{
EqualName: impl,
}

fmt.Printf("%T\n", m.EqualName) // *main.impl
}
Reply all
Reply to author
Forward
0 new messages