golang/go

spec: multiple equal integer constant switch case values should be illegal

griesemer opened this issue · 14 comments

The spec does not prohibit multiple integer constant case values from being equal:

var x int
switch x {
case 1:
case 1:
}

is not illegal according to http://tip.golang.org/ref/spec#Switch_statements . However,
running this program ( http://play.golang.org/p/MkI5XjE1TS ) results in:

prog.go:7: duplicate case in switch
    previous case at prog.go:6

using the gc compiler.

Comment 1:

The gc compiler also rejects duplicate float and string case values, but not complex
values or booleans.
In general, duplicate constants should probably be rejected.
rsc commented

Comment 2:

I certainly want to reject duplicate bools and complex too, but I think we missed the
boat.
For now let's reject duplicate int, float, and string in the spec and leave bool and
complex for Go 2.

Labels changed: added priority-later, removed priority-triage.

rsc commented

Comment 3:

Owner changed to ---.

Status changed to Started.

rsc commented

Comment 4:

Aborted attempt at http://golang.org/cl/7311067. Leaving for gri.

Status changed to Accepted.

rsc commented

Comment 5:

In addition to the shortcoming in the initial report, the switch discussion also does
not say that == must be defined on the switch expression, nor does it say that the case
expressions must be comparable to the switch expression.
rsc commented

Comment 6:

Labels changed: removed go1.1.

Comment 7:

There are two orthogonal issues here:
1) definition of the switch semantics
2) restrictions on top of 1
Regarding 1: The idea of the expression switch statement was (from day one) that it
should behave exactly like the corresponding if-else-if sequence (with the extra of
fallthrough, but that is not an inherent complication). By defining a switch in terms of
an if-else-if sequence we get an immediate and accurate definition of its behavior, it
explains why an if-else-if sequence can always be rewritten into a respective switch
statement and vice versa, and it also informs an straight-forward compiler how to
implement it  (e.g., by rewriting the AST to an if-else-if sequence). It also explains
corner-case situations such as:
    switch 1<<100 {
    case 1<<100:
    }
    var x int
    switch 1.0 {
    case x:
    }
etc., which are currently not accepted by 6g or gccgo for no good reasons. Going away
from the switch if-else-if equivalence will make the spec and programming in Go more
complicated.
2) It is possible to add orthogonal restrictions on top of the semantics proposed in 1).
The typical restriction is to disallow multiple equal constant case values as in:
    var x int
    switch x {
    case 1:
    case 1:
    }
At the moment, gc looks at duplicate integer, floating point, and string values (but
ignores duplicate complex or boolean values); gccgo ignores duplicate boolean, string,
and complex values. The situation is more complex when the tag expression is of
interface type:
    var x interface{}
    switch x {
    case 1:
    case 1.0:
    case 1e0:
    }
In this case 1 will be typed as int, while 1.0 and 1e0 will be typed as float64 and thus
1.0 and 1e0 would be the same constant, but not so 1.
There are also good reasons for not having a restriction at all: For instance, any
switch statement with more than 2 constant boolean case values will have duplicates, but
those constants may be defined globally and enable/disable functionality that might be
platform-specific. In such a scenario, we would not want a compiler error depending on
configuration. The same applies to string constants, and to some extent integer
constants.
It may be reasonable to say that the restriction should apply to numeric values only,
and perhaps even to integers only because that's a common scenario (ioata-defined
integers of an "enum" type).
After discussing this w/ r, I am leaning towards not having any restrictions enforced by
the compiler at all. r suggested that go vet might be better suited for this job.
rsc commented

Comment 8:

I think it is a mistake to remove the restrictions we have today.

Comment 9:

The main problem with the restrictions we have today is that they are not documented,
nor consistently implemented.
rsc commented

Comment 10:

Labels changed: added go1.3maybe.

rsc commented

Comment 11:

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

rsc commented

Comment 12:

Labels changed: added repo-main.

Comment 13:

Owner changed to @griesemer.

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