Sealed types

forax at univ-mlv.fr forax at univ-mlv.fr
Sat Dec 1 16:48:54 UTC 2018


> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "amber-spec-experts" <amber-spec-experts at openjdk.java.net>
> Envoyé: Samedi 1 Décembre 2018 14:26:03
> Objet: Re: Sealed types

>>>> - 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.
Exhaustiveness requires names (and visibility) but forcing names and we are back in the kingdom of nouns. 
I understand you're worry that a small patch to a compilation unit may destroy the exhaustiveness without developer seeing that, but in my opinion we should not choose to not allow anonymous classes but instead make the contract more explicit exactly like @FunctionalInterface make the contract explicit. So we should add an annotation @Exhaustiveness that ask the compiler to verify that all the implementations are named and as visible as the interface. 

> 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
> |
> 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
> |
> 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."
Not wanting exhaustiveness is not a failure. The annotation IWantExhaustivness or IDontWantExhaustivness solve that. 

>> 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.
Nestmate is currently used as a mechanism to heal the divorce between a class for the JLS and a class for the JVMS but it can be used to represent a compilation unit too. 
The programming model is that a sealed interface and all its implementations has to be in the same compilation unit (it's the premise of this discussion, or did i overlook an email ?). 

>> 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.
sealing is not nestmates, sealing has IMO two parts, one is that a a sealed interface should list all its implementation the other is the access rules between a sealed interface and its implementation. 
Netsmates can be used to represent the latter. You still need a Sealed attribute for the former. 

Rémi 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20181201/c6069a2f/attachment.html>


More information about the amber-spec-experts mailing list