Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: be clear about the meaning of _ methods in interfaces #6604

Closed
griesemer opened this issue Oct 16, 2013 · 11 comments
Closed

spec: be clear about the meaning of _ methods in interfaces #6604

griesemer opened this issue Oct 16, 2013 · 11 comments

Comments

@griesemer
Copy link
Contributor

The spec at the moment permits _ methods in signatures, like:

type A interface{
   _()
}

and such interfaces cannot be implemented, per a prior assessment of this problem (see
issue #5691). That said, there are open questions related to this that are unclear from
the spec. For instance:

1) Given A, and a type B defined like A, and variables a, b of type A, and B,
respectively, is: a = b permitted at compile-time? That is, are type A and B identical?

2) Given A, and a type B interface { _(); _() } with accordingly typed variables a, b,
is: a = b permitted? That is, are type A and B identical now?

There are several ways we can fix this in the spec. Here are two possibilities:

1) Disallow _ methods in interfaces altogether since it's never possible to implement
such an interface, never possible to call the _ method, and the contents of such
variables is always nil. Cons: we permit _ identifiers everywhere else.

2a) Permit _ methods in interfaces but any interface containing (at least) one _ method
is different from any other interface type unless they both have the same name.

2b) Permit _ methods in interfaces but any interface containing (at least) one _ method
is different from any other interface type including itself (sort of the NaN of
interfaces: NaI).

3) Maintain the _ methods in the method set, every single one of them. So interface
types that have the same non-blank methods are identical only if they have the same _
methods. That seems like a bad idea since it would require comparing signatures, and
also makes compiler internal sorting very complicated.

I am leaning towards 2a or 2b. 2b seems cleaner but precludes an easy pointer comparison
to check for type equality w/o further checking that no interface with _ method is
involved.

This is an esoteric corner case but affects how (compiler-) internally method sets are
represented and sorted.
@griesemer
Copy link
Contributor Author

Comment 1:

Approach #4: gccgo reports a duplicate method error if there are multiple _ methods in
an interface.

@griesemer
Copy link
Contributor Author

Comment 2:

go/types now implements the approach used by gccgo: blank methods in interfaces are not
treated differently from methods with non-blank names, i.e., at most one blank method is
permitted.
There's at least some support for this approach in the spec since it says:
"As with all method sets, in an interface type, each method must have a unique name."
And - in contrast to the language about struct fields - it does not explicitly exclude
blank names from the uniqueness requirement.

@rsc
Copy link
Contributor

rsc commented Nov 27, 2013

Comment 3:

Labels changed: added go1.3maybe.

@rsc
Copy link
Contributor

rsc commented Dec 4, 2013

Comment 4:

Labels changed: added release-none, removed go1.3maybe.

@rsc
Copy link
Contributor

rsc commented Dec 4, 2013

Comment 5:

Labels changed: added repo-main.

@griesemer
Copy link
Contributor Author

Comment 6:

See also related issue #6606 (for cmd/gc).

@griesemer
Copy link
Contributor Author

Comment 7:

Regarding initial comments 2a, 2b: Interface assignment is based on method sets, not
interface type identity; there's no place where interface type identity (rather than the
respective method sets matter). Thus, the initial list of possible approaches is flawed.
There seem to be only two viable approaches:
1) gccgo approach: all method names (incl. _ methods) must be unique in an interface.
That is, an interface may have at most one blank method. Because blank methods cannot be
declared for non-interface types, no concrete type can ever implement such an interface.
Because blank methods can be declared for interface types, the following code would be
legal (albeit pointless):
     type I1 interface { _() }
     type I2 interface { _() }
     var i1 I1
     var i2 I2
     i1 = i2
     i2 = i1
Interfaces may be embedded, so a blank method may be embedded as well. As with all other
interface method names, declaring 2 blank methods would lead to a double-declaration
error.
Open question in this approach: Is the blank identifier exportable? That is, could one
embed an imported interface with a blank method in an interface with another blank
method?
2) Disallow blank methods in interfaces altogether. This seems to be the simplest
approach but is somewhat "irregular" - we allow blank identifiers pretty much everywhere
else. With this approach we would lose the ability to declare an interface that cannot
be implemented by any type; however that seems not a very useful feature in the first
place.

@griesemer
Copy link
Contributor Author

Comment 8:

Regarding #7:
Blank identifiers are not capital letters and thus not exported.
And there's a 3rd option:
3) All non-blank method names in an interface must be unique. Blank methods are ignored
and are not part of the method set.
This option might be closest in behavior to how declarations handle blank names, but
slightly different from how blank fields are handled in structs (blank fields are part
of the struct for size and type identity purposes).
This option would permit interfaces with complete (and checked) method signatures, but
otherwise "invisible" methods, which might be useful during development. On the other
hand, one could just comment such methods out temporarily.

@griesemer
Copy link
Contributor Author

Comment 9:

See also issue #8060 (for go.tools/go/types).

@gopherbot
Copy link

Comment 10:

CL https://golang.org/cl/99410046 mentions this issue.

@griesemer
Copy link
Contributor Author

Comment 11:

This issue was closed by revision 2c83f1e.

Status changed to Fixed.

@griesemer griesemer self-assigned this May 22, 2014
@golang golang locked and limited conversation to collaborators Jun 25, 2016
wheatman pushed a commit to wheatman/go-akaros that referenced this issue Jun 25, 2018
The spec was unclear about whether blank methods should be
permitted in interface types. gccgo permits at most one, gc
crashes if there are more than one, go/types permits at most
one.

Discussion:

Since method sets of non-interface types never contain methods
with blank names (blank methods are never declared), it is impossible
to satisfy an interface with a blank method.

It is possible to declare variables of assignable interface types
(but not necessarily identical types) containing blank methods, and
assign those variables to each other, but the values of those
variables can only be nil.

There appear to be two "reasonable" alternatives:

1) Permit at most one blank method (since method names must be unique),
and consider it part of the interface. This is what appears to happen
now, with corner-case bugs. Such interfaces can never be implemented.

2) Permit arbitrary many blank methods but ignore them. This appears
to be closer to the handling of blank identifiers in declarations.
However, an interface type literal is not a declaration (it's a type
literal). Also, for struct types, blank identifiers are not ignored;
so the analogy with declarations is flawed.

Both these alternatives don't seem to add any benefit and are likely
(if only slightly) more complicated to explain and implement than
disallowing blank methods in interfaces altogether.

Fixes golang#6604.

LGTM=r, rsc, iant
R=r, rsc, ken, iant
CC=golang-codereviews
https://golang.org/cl/99410046
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants