- it works for anonymous class declared in the same
compilation unit ?
Anonymous classes are a good question. On the one hand, I can
imagine when they might be useful. On the other, it means there's
no way anyone -- including the current class, to which all the
subtypes are accessible -- will be able to switch exhaustively
over them. I think we should consider banning them, as you can
always fall back to a named class. The exhaustiveness part is
important, and too easy to forget about when you're writing the
class.
Exhaustiveness is one consequence of a sealed interface, but having a
sealed interface, i.e. constraining all subtypes to be defined in the
same compilation unit is useful even without exhaustiveness.
It's a way to allow to make an interface visible without having to
care about implementations you do not know.
In a previous mail, you said that if an implementation class is not
visible from a switch, then the compiler will just ask for a default.
An anonymous class (or a local class of a method for completeness) is
just a class which is not visible from any switches.
This is all obviously true, but also a kind of false equivalency. Yes,
constraint can useful without exhaustiveness. But, if you make it too
easy to undermine exhaustiveness, people will do this without realizing
it, and likely for little benefit. It is really really common that when
declaring APIs, users forget about what problems they are creating for
their callers. Examples include:
- "Why can't I declare defaults for Object methods"
(https://stackoverflow.com/questions/24016962/java8-why-is-it-forbidden-to-define-a-default-method-for-a-method-from-java-lan/24026292#24026292)
-- because you'd break subclasses.
- "Why can't default methods be synchronized"
(https://stackoverflow.com/questions/23453568/what-is-the-reason-why-synchronized-is-not-allowed-in-java-8-interface-methods?noredirect=1&lq=1)
-- because it doesn't mean what you think it means.
- Use-site ambiguity overload errors resulting from overloads like
m(Function) and m(Predicate) -- because then you create an API that no
client can use it with lambdas, oops.
In each of these cases, the problem is a failure to consider what the
impact of the declaration-site decisions are on callers. So, I think
the question of anonymous classes is more subtle than you're giving it
credit for.
So yes, accessibility can undermine exhaustiveness -- outside the
capsule. (Inside the capsule, you still get exhaustiveness.) But I see
no reason why we should leap from "yes, sometimes it fails" to "so let's
make it really easy to make it fail all the time."
For me, a sealed type and all its implementation are nestmates from
the VM point of view (it's stronger that you are proposing), they are
part of the same compilation unit.
Then we cannot allow subtypes outside the nest, because that would be in
conflict with the nestmate design. That's a possible point in the
design space, but I think its overly restrictive, and eliminates some
really important use cases. Plus, only .001% of Java developers even
know what a nest is, so it seems a little questionable to distort a
programming model feature to match a VM feature that no one is aware of.
see above, if we allow anonymous class, we have to allow lambdas (we
already support refactoring from one to the other).
Given that the class of a lambda is only knows at runtime, it means
that the nestmate attributes and the sealed attributes have to be
updated at runtime.
A further argument that trying to say "sealing == nestmates" is pushing
on the wrong end of the lever.