Expand what permit can specify in Sealed Classes
Tagir Valeev
amaembo at gmail.com
Wed Nov 11 16:17:15 UTC 2020
Hello!
Of all hierarchy-based permits I see that only one of them is useful:
interface X permits extends A (where A is a non-final, possibly
abstract class). In our codebase we have a number of interfaces that
are used to extend the functionality of the classes that have common
ancestor. This usually happens when you already have a complex class
hierarchy (with a single base superclass A) and want to specialize
some of the subclasses providing additional functionality. So you end
up with a new interface X, but the interface is meaningful only for
inheritors of A. You cannot refactor A to an interface, as it holds
the state and you will break the compatibility for clients. But
current Java cannot help you to enforce that X inheritors must be A
inheritors as well, so you can only hope that clients read the
documentation and program carefully. If we could enforce that all X
inheritors must extend A this would 1) make programs more robust 2)
help people understanding your API (a compilation error like XImpl
must extend A would be a great pointer on how to use the API) and 3)
may improve the performance (if VM disables loading classes that
implement X but don't extend A then checkcast from X to A could be
completely eliminated without any uncommon trap) 4) allow using
exhaustive cast operator (was discussed before) from X to A.
Examples from IDEA Community sources:
TypedLookupItem interface is applicable for LookupElement inheritors only
https://github.com/JetBrains/intellij-community/blob/master/java/java-impl/src/com/intellij/codeInsight/lookup/TypedLookupItem.java
TypedLookupItem was introduced many years after LookupElement which is
very old and heavily used in third-party plugins. It provides some
additional functionality for completion and when it was introduced,
some existing leafs in LookupElement hierarchy (including third-party
plugins) were changed to implement this interface. Probably it would
be cleaner were LookupElement an interface but what's done is done.
ControlFlowException interface: a marker for exceptions that should
not be logged
https://github.com/JetBrains/intellij-community/blob/master/platform/util/src/com/intellij/openapi/diagnostic/ControlFlowException.java
If somebody tries to log it, 'Report to JetBrains' feature is
activated, so we get an alarm and will fix it. Naturally, this
interface is only applicable for Throwable descendants. Of course, we
cannot make Throwable an interface. Also, it would be very
inconvenient to declare ControlFlowException as a subclass somewhere
in Throwable hierarchy, as some implementors extend RuntimeException
while others extend Exception directly.
With best regards,
Tagir Valeev.
On Wed, Nov 11, 2020 at 8:42 PM Brian Goetz <brian.goetz at oracle.com> wrote:
>
> We explored this option (e.g., "permits package") very early on in the
> feature design, and backed away from it.
>
> Essentially, sealed types has a bimodal design center: extension
> control, and exhaustiveness. The latter is about "I know that A=B+C, so
> a switch on A that covers B and C is exhaustive." The compiler can use
> this information to provide better type checking. While the first is
> more immediately obvious to Java developers (because we already have a
> system of access control), the second is actually more important in
> terms of building reliable code. (If we had to pick only one of these,
> we'd pick the second.)
>
> The extensions you are suggesting are all about extension control and
> not at all about exhaustiveness. While that's not a fatal
> characteristic for these ideas, it is a red flag, because it's speaking
> exclusively to the minority motivation.
>
> Basically, "permits module" or "permits package" is a purely syntactic
> convenience; you can express what you mean without it, and I don't think
> that the few cases where this list is long justifies the feature. For
> the more complex examples ("permits supertypes of subtypes of classes
> with a Q in their name"), I think you'd be hard-pressed to come up with
> more than a handful of examples where it would be sensible.
>
>
>
> On 11/11/2020 2:17 AM, Suminda Sirinath Salpitikorala Dharmasena wrote:
> > Hello,
> >
> > Can the scope of the permit be expanded so following use cases are
> > supported:
> >
> > - package - permits package x.y.x, package a.b.c, S, T (S, T are classes
> > or interfaces)
> > - modules - permits module x.y.x, module a.b.c, S, T
> > - subtypes - permits extend A, extend B, S, T
> > - supertypes - permits super A, super B, S, T
> > - subtypes of supertype - permits extend super A, extend super B
> > (effectively not a subtype of A or B. Combining with extends can limit the
> > type hierarchy - e.g.: permits extends A, extends super B)
> > - class or interface - permits S, T (current implementation and
> > functionality)
> >
> > Suminda
>
More information about the amber-dev
mailing list