At the time, Kevin made an excellent argument that "developers have learned that ICCE means 'your class path is borked, dude, recompile'", and a novel enum value was indicative of a borked class path.  This was compelling in context, and we went this way.

As we've moved on, we realize there is a bigger picture here, so I support this change.

On 11/14/2022 2:14 PM, Kevin Bourrillion wrote:
Makes complete sense to me. A switch that was acceptably exhaustive when it was compiled can still get an unhandleable value at runtime for I think a small handful of different reasons, and with your change they would all throw the same thing, correct? I don't fully remember the points I made about ICCError, but surely this overrides them!


On Mon, Nov 14, 2022 at 4:38 AM Gavin Bierman <[email protected]> wrote:

    Dear Experts,

    As we put the final polish on features for JDK20, we noticed that
    we have an opportunity to make a very small breaking change (as
    part of the preview feature) to simplify our lives. I’m writing to
    see what you think.

    tldr: A switch expression over an enum class should throw
    MatchException rather than IncompatibleClassChangeError if no
    switch label applies at runtime.

    Details:

    When we introduced switch expressions, we opted for a design where
    the switch body had to be exhaustive. When switching over an enum
    type, a switch body with case labels supporting all the enum
    constants for the enum type is considered exhaustive, meaning a
    default clause is not needed.

    However, there is a possibility that the enum class is changed
    after compilation of the switch expression, and a new enum
    constant added. Then when executing the switchexpression, no label
    would apply.

    The question we faced in JDK14 was what to do at this point. We
    decided on IncompatibleClassChangeError as that was a pre-existing
    exception that was generally understood by developers as a signal
    that things have got out of sync and re-compilation is needed.

    Back to the present day, with the support of pattern switches, we
    can now write switches over a sealed type. When switching over a
    sealed type, a switch body with case labels with type patterns
    matching all the permitted subclasses is considered exhaustive,
    meaning a default clause is not needed.

    If the sealed hierarchy has been changed after compilation of the
    switch, it is possible that when executing the switch that no
    label would apply. In this case we have settled on throwing a
    MatchException.

    Throughout our design process, we have noticed the connection
    between enum classes/enum constants and sealed class/permitted
    subclasses – they are essentially the same thing up the term/type
    hierarchy. Moreover, in a future release, we plan to support case
    labels with a mix of sealed class type patterns and enum constants.

    But we now have an inconsistency - one throws
    IncompatibleClassChangeException in a bad situation and the other
    MatchException which will make this future development almost
    impossible. We need these cases to throw the same exception:
    MatchException. So we propose to make the small breaking case to
    the language that switch expressions over enum classes throw
    MatchException should no switch label apply in the switch body.

    People who deliberately change their enum classes by adding new
    constants, and do not recompile their switches over this enum
    class, and rely on this throwing ICCE will notice this breaking
    change. We think this is a vanishingly small set of developers.
    The vast majority of developers, on the other hand, will thank us
    for this unification, especially if it enables other new features
    down the road.

    What do you think?

    Thanks,
    Gavin



--
Kevin Bourrillion | Java Librarian | Google, Inc. |[email protected]

Reply via email to