Sealed interfaces with hidden implementation superclasses

Mark Raynsford mark at
Tue Jan 4 13:10:32 UTC 2022

(Apologies for the possible double post: I tried to post this to
amber-dev@ and the message apparently never made it there. I asked
amber-dev-owner@ but got no response there either).

I've run across some behaviour I didn't anticipate with regards to
sealed interfaces. I suspect that it's expected behaviour, but I
feel like maybe the type system is overly constraining in this
particular case.

Imagine a small UI library with a sealed set of primitive components:

  sealed interface Component permits Button, TextView, ImageView {}
  non-sealed interface Button extends Component {}
  non-sealed interface TextView extends Component {}
  non-sealed interface ImageView extends Component {}

The set of primitive components is sealed because doing so simplifies
other parts of the system; more complex components are just aggregates
of the primitives.

Then, in one or more separate modules, we have some platform-specific
implementation classes:

  final class X11Button implements Button
  final class X11TextView implements TextView
  final class X11ImageView implements ImageView

  final class QNXButton implements Button
  final class QNXTextView implements TextView
  final class QNXImageView implements ImageView

This is all fine so far. The problem occurs when one of those
implementations wants to introduce a private abstract superclass 
that contains shared implementation code but that - importantly - isn't
actually intended to ever be observed on its own outside of the module.

Naturally, that superclass wants to implement Component so that it can
provide implementations of the common methods:

  abstract class QNXComponent implements Component
  final class QNXButton extends QNXComponent implements Button
  final class QNXTextView extends QNXComponent implements TextView
  final class QNXImageView extends QNXComponent implements ImageView

The compiler (rightfully) complains that QNXComponent isn't in
the "permits" list of Component. We can obviously remove
the "implements Component" from QNXComponent, but this then
means adding boilerplate @Override methods in each of QNXButton,
QNXTextView, etc, that call the now-non- at Override methods in
the abstract QNXComponent class.

Mark Raynsford |

More information about the amber-spec-experts mailing list