Switch on java.lang.Class

Brian Goetz brian.goetz at oracle.com
Tue Apr 10 12:25:48 UTC 2018

> Though I don't see why usefulness of the feature in a low-level 
> libraries should be the warning sign.

I don't dispute it's usefulness, but I'm sure you agree that "usefulness 
 > 0" is not the bar for putting a feature in the language -- it is way, 
way higher than that.

My bigger concern is that it is error-prone -- especially if we release 
type-test patterns and Class constant patterns at the same time.  Many 
users will be tempted to use Class patterns as a less ugly alternative 
to instanceof tests -- and then their code will be subtly wrong.  When 
given the choice of what looks like "old fashioned switch with a new 
type", and "new-fangled type-test patterns", many users will lean 
towards the former because its familiar.  And get the wrong thing.

So the problem is not that its only useful to low-level users; its that 
others users may be tempted to use it, and get the wrong thing.  (This 
isn't theoretical.  "Type Switch" has been an RFE for years; in the 
examples presented as justification for the feature, many wrongly 
conflate it with instanceof.)

> In any case I'm pretty sure that switch on class will be more 
> applicable, than the switch on floats. But you are doing theswitch on 
> floats. Why? For consistency, of course. You want to support all 
> literals in switch. But class literals are also literals, according to 
> JLS 15.8.2, so it is inconsistent not to support them (especially 
> taking into account that their usefulness is not the lowest of all 
> possible literals).

"For consistency" arguments are always weak justifications for including 
a feature, because you can always find a precedent or rule to be 
consistent with.  The justification is not merely for consistency; it is 
to avoid introducing _new_ asymmetries.  It would be silly to not allow 
float literals as patterns; then you couldn't match against 
`Complex(0.0f, 0.0f)`.

So the choice is not about float in _switch_, but about float as a 
_pattern_.  Once you admit the latter, it is hard to say no to the 
former.  (Same with null; we're not doing `case null` for its own sake, 
its to support `null` as a pattern; using it in `case` is a consequence 
of that.)

So, should class literals be a pattern?  That would also mean that you 
could say

     if (x instanceof Foo.class) { ... }

and it would mean something subtly different than

     if (x instanceof Foo) { ... }

That's not so good.  Or the same mistake in switch:

     switch (anObject) {
         case "Foo":
         case String.class:

which means "does anObject equal the constant String.class".  The 
confusion between `String` and `String.class` as patterns is a pretty 
serious risk.  And again, introducing both kinds of patterns at once 
makes it worse.

So, while I think its a consistent and useful feature, I also don't 
think its a necessarily good idea to expose everyone to this confusion.

More information about the amber-spec-observers mailing list