Minsoo Cheong
12/07/2021, 9:15 AMwhen
statements' break OCP(open-closed-principle) ?
I saw the new sealed when compiler feature on Kotlin 1.6.0 and shared it to my team, thinking we could use it, but there was an opinion that this kind of logic breaks the ocp rule because,
If you add new inheritors to the sealed class(or interface), you would have to change all the when statements that take that sealed class(which is the parent class) and thus, ocp is broken
Would this be true? We agreed that the oop rules were made before sealed classes/interfaces were introduced and this might be the "trend" of programming languagues, but still some are hesitant to use it.
Any kind of related opinion & reading material is welcome to be shared,,
thanks!Albert Chang
12/07/2021, 9:20 AMJoffrey
12/07/2021, 9:20 AMwhen
statement already breaks the open close principle, because you're listing all possible entries (switch
is considered harmful in OOP because it ruins how polymorphism works, it doesn't abstract away the behaviour behind a swappable interface).
Using an else
in a when
is just a way to feel safe but more often than not it's just else -> error("unknown case X")
. Not using an else
at all (with existing non-exhaustive statements) is even more sneaky! If you add new subclasses or enum values, your when
statement will likely fail or not behave as expected - at runtime. Using sealed `when`s is a way to detect all those changes at compile time instead.dmitriy.novozhilov
12/07/2021, 9:22 AMwhen
with sealed type:
1. You want to check some inheritors and don't care about others
2. You really need to check all inheritors (e.g. you want to switch on all kinds of response from client or smth like that)
If you use when
as expression then in first case you just add some empty else
, and if someone add new inheritor in future compiler warn you about all cases from 2. which should be fixed. And if when
was a statement then compiler didn't can distinguish 1. from 2., which might lead to errors when you forgot to process this new inheritor and silently ignored it. So IMO adding else -> {}
in cases 1. is not much price to keep your code correct in cases when you really need to check them allMinsoo Cheong
12/07/2021, 9:28 AMJoffrey
12/07/2021, 9:32 AMwhen
statement already forces you to check all usages if you add a new subclass or enum entry. Because even with non-exhaustive `when`s, you can't know (without looking) whether the new case should be "ignored" (leaving the when
as-is) or included as a new branch. The only difference between exhaustive and non-exhaustive is that the former helps find these issues earlier.
Note that using an else
in a when
statement is almost as bad as a non-exhaustive when.thanksforallthefish
12/07/2021, 9:34 AMwhen
is a form of pattern matching (albeit primitive) and I feel some patterns/principles, while valid, were thought to overcome limitations in the language.
the article makes a good example of the visitor pattern being used to overcome the lack of pattern matching in java, which becomes “obsolete” with pattern matching (then it is still a matter of preferences, and of use case).when
, but if you add more implementations than operations I would choose visitor/polymorphismMichael de Kaste
12/07/2021, 10:06 PMvar x: Int = 0
when(someSealedClass){
case1 -> x = 3
case2, case3, case4 -> x = 5
else -> { }
}
I don't want to mutate the int in some cases, but now I am forced to add an else -> { }
I also really don't like using if's here
var x: Int = 0
if(someSealedClass is case1){
x = 3
} else if(someSealedClass is case2 || someSealedClass is case3 || someSealedClass is case4){
x = 5
}
Joffrey
12/07/2021, 10:33 PMwhen
expression instead