Compiler could be smarter when dealing with exhaustive switch and final variables?
David Alayachew
davidalayachew at gmail.com
Sat Oct 8 14:34:10 UTC 2022
Hello Rémi,
First off, apologies for double sending - I sent to just you instead of to
the mailing list too.
> Hi David,
> i think this is similar to
> https://bugs.openjdk.org/browse/JDK-8294670
> that i've reported recently.
Whoops, apologies. I even see linked in the bug report that the issue was
even reported on the same mailing list barely a week ago. I've been falling
behind on reading the mailing lists. I'll be sure to catch up before
posting bug reports in the future.
> You can even abuse of the switch + record pattern
> to extract numA and numB :)
What a clever idea lol. Expressiveness be damned, but your solution
actually works.
I have been trying to use local records more frequently, but there's this
one annoying edge case that has made me shy away from using them as much (
https://bugs.openjdk.org/browse/JDK-8287885). But if there's flexibility
like this to be found, then it sounds like I should lean more into local
records.
> BTW, this kind of code is less unreadable in languages like Scala where
> the switch is postfix to the value switched upon and not prefix.
I'm still digesting the comment about type classes that you mentioned last
time. Seems like Scala has a lot to teach me as a language.
Thank you for your response and its insight!
David Alayachew
On Sat, Oct 8, 2022 at 6:22 AM Remi Forax <forax at univ-mlv.fr> wrote:
>
>
> ------------------------------
>
> *From: *"David Alayachew" <davidalayachew at gmail.com>
> *To: *"amber-dev" <amber-dev at openjdk.org>
> *Sent: *Saturday, October 8, 2022 9:07:31 AM
> *Subject: *Compiler could be smarter when dealing with exhaustive switch
> and final variables?
>
> Hello Amber Dev Team,
>
> When if/else statements and final variables combine, the compiler can make
> some helpful assertions. Consider the following code.
>
> sealed interface SomeInterface {}
> record First() implements SomeInterface {}
> record Second() implements SomeInterface {}
>
> private void exhaustiveIfWithFinalUninitialized()
> {
>
> SomeInterface abc = new First();
>
> final int numA;
> final int numB;
>
> if (abc instanceof First)
> {
>
> numA = -1;
> numB = -1;
>
> }
>
> else if (abc instanceof Second)
> {
>
> numA = -2;
> numB = -2;
>
> }
>
> else
> {
>
> throw new IllegalStateException("This shouldn't be possible!");
>
> }
>
> System.out.println(numA + "");
> System.out.println(numB + "");
>
> }
>
> The above code compiles with no errors whatsoever. The compiler is smart
> enough to realize that, no matter what, numA and numB will most certainly
> be populated by the time we reach the print statements below the if
> statements.
>
> However, the compiler does not make the same realization when working with
> exhaustive switches. But since the switch statement is exhaustive,
> shouldn't the compiler be able to make the same realization here? If
> anything, the switch should be capable of all of the above and more,
> correct?
>
> private void exhaustiveSwitchWithFinalUninitialized()
> {
>
> final int numA;
> final int numB;
>
> SomeInterface abc = new First();
>
> switch (abc) //compiler error unless we uncomment the default
> {
>
> case First f ->
> {
>
> numA = 1;
> numB = 0;
>
> }
>
> case Second s ->
> {
>
> numA = 0;
> numB = 1;
>
> }
> /*
> default ->
> {
>
> numA = 2;
> numB = 2;
>
> }
> */
> }
>
> System.out.println(numA + "");
> System.out.println(numB + "");
>
> }
>
> I would like it if the compiler could make the same realizations it did
> for the if statement. I should also add, this seems to apply to all forms
> of exhaustive switch except for those with default clauses.
>
>
> Hi David,
> i think this is similar to
> https://bugs.openjdk.org/browse/JDK-8294670
> that i've reported recently.
>
>
> Obviously, this is easy to work around - I could just make a switch
> expression for each variable, and then just populate them individually.
> Alternatively, I could just put a default clause any time I need that
> compiler realization, though I give up some benefits from exhaustive switch
> as a result.
>
>
> As a workaround, you can also group the values into a record (that can be
> local to the method) and use an expression switch and initialize the local
> variable after the switch.
>
> You can even abuse of the switch + record pattern to extract numA and numB
> :)
>
> record Pair(int numA, int numB) {}
> switch(switch(abc) {
> case First -> new Pair(1, 0);
> case Second -> new Pair(0, 1);
> }) {
> case Pair(int numA, int numB) -> {
> System.out.println(numA);
> System.out.println(numB);
> }
> }
>
> BTW, this kind of code is less unreadable in languages like Scala where
> the switch is postfix to the value switched upon and not prefix.
>
> Thank you all for your time and help!
> David Alayachew
>
>
> regards,
> Rémi
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20221008/62ebe641/attachment-0001.htm>
More information about the amber-dev
mailing list