David Kubecka
02/22/2023, 10:43 AMenum class DateAttribute : UpcomingPaymentAttribute
data class DateKey(val startDate: LocalDate, val granularity: DateAttribute)
...
// it is UpcomingPaymentAttribute
when (it) {
DateAttribute.DAY -> DateKey(LocalDate.now(), it) // here compiler complains that it is UpcomingPaymentAttribute, not DateAttribute
CLOVIS
02/22/2023, 10:49 AMit
a var
? What's the compiler message?David Kubecka
02/22/2023, 10:56 AMType mismatch: inferred type is UpcomingPaymentAttribute but DateAttribute was expected
it
is just the standard "default" variableCLOVIS
02/22/2023, 10:57 AMGoetz Markgraf
02/22/2023, 12:43 PMit
be of type DateAttribute
? I don’t see any cast.
it
is of Type UpcomingPaymentAttribute
. In the when
expression, I see that it
is compared to a value of DateAttribute.DAY
. But that does not include, casting it
to DateAttribute
.
If you had a is DateAttribute
in the when
expression, than the compiler would cast.David Kubecka
02/22/2023, 12:48 PMit == DateAttribute.DAY
then surely it is DateAttribute
🙂 Can I somehow help the compiler realize that (other than manual cast)?CLOVIS
02/22/2023, 12:56 PM===
, then sure.Goetz Markgraf
02/22/2023, 1:01 PMinterface Parent
enum class Child : Parent {
THREE, FOUR
}
fun doIt(param: Child) {
println (param)
}
val a: Parent = Child.THREE
when (a) {
Child.THREE -> doIt(a)
Child.FOUR -> {}
}
Two solutions:
when {
a is Child && a == Child.THREE -> doIt(a)
or
when (a) {
Child.THREE -> doIt(a as Child)
I’d prefer the second variant.
I agree with you that the compiler actually should be able to cast that.CLOVIS
02/22/2023, 1:04 PMequals
with a dumb implementation (which would indeed be dumb, but it could happen), it'll crash with ClassCastException, which will be hell to debug.David Kubecka
02/22/2023, 1:48 PMyou can override equalsThat's the explanation I was looking for. Thanks! Although, the consequences are kind of unfortunate because either I will do the explicit cast/check, or go with
===
losing the exhaustiveness of when
CLOVIS
02/22/2023, 1:50 PMwhen (it) {
is YourEnum -> when (it) {
YourEnum.FirstElement -> …
YourEnum.SecondElement -> …
}
else -> …
}
It's much easier to understand what happens, you have the smart cast and exhaustive checks, and it's probably faster (the inner when
on the JVM can be compiled to a native switch
)Goetz Markgraf
02/22/2023, 1:52 PMCLOVIS
02/22/2023, 1:52 PMis
check, you shouldn't eitherKlitos Kyriacou
02/22/2023, 3:31 PMequals
can lead to unexpected behaviour? I couldn't get it to misbehave the way @CLOVIS suggests:
interface Parent
object O : Parent {
override fun equals(other: Any?): Boolean {
return true
}
}
enum class Child : Parent {
ONE, TWO;
}
var o: Parent = O
fun main() {
println(o.equals(Child.ONE)) // true
println(o == Child.ONE) // false!
val n = when (o) {
Child.ONE -> 1
Child.TWO -> 2
O -> 3
else -> 4
}
println(n) // 3, not 1
}
when
expression will choose the enum value only when the variable is an actual enum type.CLOVIS
02/22/2023, 3:37 PMKlitos Kyriacou
02/22/2023, 5:27 PM==
operator doesn't seem to call equals
(playground). This contradicts the language spec and the documentation.