Why does the following `when` statement require an...
# getting-started
k
Why does the following
when
statement require an
else
?
Copy code
data class Person(val name: String, val birthDate: LocalDate)

fun update(person: Person, property: KProperty1<Person, *>, value: Person): Person =
    when (property) {
        Person::name -> person.copy(name = value.name)
        Person::birthDate -> person.copy(birthDate = value.birthDate)
        else -> error("Why isn't this exhaustive?")
    }
y
While I agree with you that it should, note that that's an interface, so technically one could implement it.
1
thank you color 1
a
No, that is not exactly true, since this is a data class (not an interface or an open class), and data-classes can not be open, so it cannot have an inheriting subclass. On the other hand, this
when
is an expression, not a statement (since this update-function is defined by an expression), and for
when
-expressions, they always need to be exhaustive, and they always need to have an
else
-branch, except for the cases, when the
when
-subject (here, the subject is
property)
is a
Boolean
, enum class, sealed class, or one of their nullable counterparts, but here it is a
KProperty1
, which does not meet this requirement. Hence, the
else
-Branch is needed. For details, see the documentation at https://kotlinlang.org/docs/control-flow.html#when-expressions-and-statements and https://kotlinlang.org/docs/data-classes.html
y
I meant that
KProperty1
is an interface, as the link shows, and hence one could write a subclass for it. Also @Klitos Kyriacou, I think extension properties might count too, so exhaustiveness is definitely not a given.
💯 2
a
Oh I am sorry, I did not see the link behind your interface, I thought you were talking about the data-class from the example.
✔️ 1
y
Confirmed that extension properties count:
Copy code
import kotlin.reflect.*
data class Person(val name: String, val birthDate: String)

val Person.fullname: String get() = name

fun update(person: Person, property: KProperty1<Person, *>, value: Person): Person =
    when (property) {
        Person::name -> person.copy(name = value.name)
        Person::birthDate -> person.copy(birthDate = value.birthDate)
        else -> error("Why isn't this exhaustive?")
    }
fun main() {
    val person = Person("foo", "bar")
    update(person, Person::fullname, person)
}
Also, I think you're looking for Optics for your use case
👍 1
k
Thanks. I was actually thinking of using these properties as a compile-time type-safe way to express column names in a DTO (using
property.name
). But since this can be sabotaged by a user inheriting from
KProperty1
or by using an extension property, I can't have compile-time safety.