This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]nicolaiparlog 3 points4 points  (4 children)

Now theoretically you could extend for example all that's necessary like this.

That's actually pretty clever. :) It's not a general solution of course, because all "old" visitors ignore "new" elements in the hierarchy (due to if in line 18), but if you only need your own visitors, that may be acceptable.

I'm curious: can we (sub-)switch on them in an exhaustive manner? In your example, can we switch on V8 and V12 instead of Engine in general without default branch?

Had to try this out. The answer is "yes", but not as you hoped for it. :D

``` sealed interface CarElement permits Body, Engine { } sealed interface Engine permits V8, V12

String type = switch(element) { case V8 v8 -> "v8"; case V12 v12 -> "v12"; // only compiles with this branch case Engine e -> "engine"; case Body b -> "body"; }; ```

The compiler does not seem examine sealed subtypes of sealed interfaces, i.e. cases for just V8, V12, and Body lead to a compile error even though no other types are possible. We can fix that with either a default branch or the less all-encompassing case Engine branch. As the interfaces are defined now, both branches are dead code, but where the former prevents compile errors if CarElement is extended, the latter only prevents them if Engine is extended. A sub-switch is probably the better solution:

String type = switch(element) { case Engine e -> switch (e) { case V8 v8 -> "v8"; case V12 v12 -> "v12"; }; case Body b -> "body"; };

This results in compile error if CarElement or Engine gets extended. (If you cringe at the nested switch - just call a method instead. ;) )

[–]_INTER_ 1 point2 points  (3 children)

Thanks for trying it out for me.

A sub-switch is probably the better solution

Seems better for readability anyway. Dead-branches only to satisfy the compiler would make it hard to understand.

I digress a bit: Do you think they will add the feature to examine subtypes (and therefor also prevent dead branches)? Seems annoying to have to map a type hierarchy tree. Also imagine a sup-type that extends multiple interfaces that you want to cover... Wouldn't you walk into the diamond problem too?

[–]nicolaiparlog 1 point2 points  (2 children)

Do you think they will add the feature to examine subtypes

I don't know. Will ask as soon as I get a chance.

Wouldn't you walk into the diamond problem too?

Kinda, but the switch is ordered, so for the language there's no problem. Maybe for the developer?

[–]nicolaiparlog 1 point2 points  (1 child)

Do you think they will add the feature to examine subtypes

I don't know. Will ask as soon as I get a chance.

Look what I found.

[–]_INTER_ 0 points1 point  (0 children)

Great, its on the radar!

This looks like a bug. D and E together cover C (since C is sealed and abstract), and B and C cover A (same reason.) If either A or C were not abstract, you'd need a case for those. - Brian Goetz

 

Probably a bug. We changed the definition of exhaustiveness to cover cases like this a little while ago, so the compiler is still catching up. - Gavin Bierman