RFR: JEP 360: Sealed Types (Preview)

Kłeczek, Michał michal at kleczek.org
Wed Apr 15 14:06:40 UTC 2020


Actually I was talking about _adding_ a new permitted subtype (and this 
is why I think it might be surprising and worth mentioning):

// Maintenance domain A
sealed interface X permits X.A, X.B
     // added in version 1.1
     , X.C
{
     public class A implements X {}
     public class B implements X {}
     // added in version 1.1
     public class C implements X {}
}

public X xFactory() {
   //returns one of X permitted subtypes
}


// Maintenance domain B built against A 1.0
int z = switch (x) {
     case A a: ...
     case B b: ...
     // no default
     // boom
}

Given the fact that removal of a permitted subtype is also an 
incompatible change (since either a public type is removed or it can no 
longer be a subtype of the same sealed supertype) - it means the set of 
permitted types has to be set in stone.

Exhaustiveness check is a double-edged sword: I wouldn't be surprised if 
in a not-so-distant future we have JEPs similar to:
https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md

Thanks,
Michal

On 15/04/2020 14:58:01, "Brian Goetz" <brian.goetz at oracle.com> wrote:

>This is a good observation, but I think you've overstated somewhat 
>(and, to some degree, this incompatibility may actually be doing your 
>clients a favor.)
>
>Here's the case I think you're concerned about:
>
>// Maintenance domain A
>sealed interface X permits X.A, X.B {
>     public class A implements X {}
>     public class B implements X {}
>}
>
>// Maintenance domain B
>int z = switch (x) {
>     case A a: ...
>     case B b: ...
>     // no default
>}
>
>Your concern is that the compiler will accept this switch as exhaustive 
>(so far, that's good), and later, if we refactor the X subtypes, this 
>might be a source-incompatible change.  (It always has been an 
>incompatible change to remove a class, or to remove a supertype from a 
>class, so that's not what we're talking about here -- we're talking 
>about removing it from the permits clause.)
>
>Indeed, using the sealing information to switch exhaustively over a 
>sealed type is a form of *tight coupling*; client code that wants to 
>take advantage of this information should either be part of the same 
>maintenance domain as the hierarchy, or be confident that the API is 
>set in stone, or be ready to change when the hierarchy changes.  These 
>are all reasonable choices to make with one's eyes open, but I think 
>your concern is that this sort of tight coupling could arise 
>_accidentally_ from ordinary use.
>
>And, that's true.  However, I think it's not as bad as you think (and 
>this has already been discussed a fair bit on the EG list.)  First, 
>merely dropping A from the permits clause is a binary-compatible 
>change, so existing binaries will continue to run just fine.  It is 
>source-incompatible, but I would argue that this is, in many cases, 
>better than the alternative.  Getting a compilation error here is type 
>checking at work; the compiler has identified an assumption baked into 
>your program that is no longer valid.  If it's a matter of having 
>dropped a permitted subtype, the change to your code is easy -- just 
>drop the case, and you are correct again.  If its a matter of having 
>added a permitted subtype, the change is also easy; if you don't want 
>to handle the new case, add a default clause that throws (which is what 
>you would have done in the first place if you didn't have the option to 
>lean on exhaustiveness checking in the compiler.)
>
>
>It is certainly good to write down some promoted practices for using 
>sealed types, and this is something to consider pointing out, but the 
>JEP is not the place for that; if it were, JEPs would be 100 pages (and 
>then people would complain they were too big, as in fact some people 
>already do.)  For other features (e.g., var, text blocks) there have 
>been separate "style guide" documents that have the luxury describe the 
>nuances in more detail.
>
>
>
>On 4/15/2020 8:32 AM, Kłeczek, Michał wrote:
>>Hi Vicente,
>>
>>IMHO there is one thing I think is worth pointing out in the 
>>documentation (as it is going to be cited on thousands of web sites):
>>
>>One has to be very careful when exposing sealed types with only public 
>>permitted subtypes in public APIs.
>>Doing that makes it impossible to change the list of subtypes - both 
>>removal and adding of a subtype is an incompatible change.
>>
>>I think it might be surprising for many library developers and I've 
>>raised the concerns about this before - maybe it is a good idea to 
>>make it more apparent.
>>
>>Thanks,
>>Michal
>>
>>On 13/04/2020 18:03:18, "Vicente Romero" <vicente.romero at oracle.com> 
>><mailto:vicente.romero at oracle.com> wrote:
>>
>>>Hi all,
>>>
>>>The sealed types JEP was already reviewed a while back when we were 
>>>planning to include it in JDK14. It finally fell off that boat but it 
>>>is being considered now for JDK15. There have been some changes since 
>>>then mostly related to subtypes of a sealed type. Before we were 
>>>planning to infer finality, sealness or non-sealness in the subtypes. 
>>>We steered away from that direction in favor of explicit declaration 
>>>at the subtype. I would like to ask for another review of the current 
>>>version of the JEP that reflects these changes. The JEP is at [1] and 
>>>the last version of the spec is at [2],
>>>
>>>Thanks,
>>>Vicente
>>>
>>>[1] https://bugs.openjdk.java.net/browse/JDK-8227043
>>>[2] 
>>>http://cr.openjdk.java.net/~gbierman/jep360/jep360-20200228/specs/sealed-types-jls.html
>>>
>>
>


More information about the amber-dev mailing list