christoph.pickl
02/02/2018, 5:19 AMdata class Person(
val name: String?,
val age: Int?
)
fun moduleExternal() = Person("", 1)
and a target function with a signature of:
fun safeCall(x1: String, x2: Int) {}
the following WON'T compile due to not being able to smart cast external module's properties:
fun solution_no_smartcasts() {
val person = moduleExternal()
if (person.name != null && person.age != null) {
safeCall(person.name, person.age) // ERROR!
}
}
in order to get rid of the smart cast problem first, i came up with the following idea of destructuring:
fun solution_destructure() {
val (name, age) = moduleExternal()
if (name != null && age != null) {
safeCall(name, age)
}
}
ok, but how about that "low level" if? apple's swift would solve it this way:
if let name = person.name as? String, let age = person.age as? Int {
// name and age are non-optional in here
}
so i thought about an extended if which "kind of" solves it:
fun <T1, T2> ifNotNull(x1: T1?, x2: T2?, action: (T1, T2) -> Unit) {
if (x1 != null && x2 != null) {
action(x1, x2)
}
}
fun solution_kotlin_lets() {
val person = moduleExternal()
ifNotNull(person.name, person.age) { name, age ->
safeCall(name, age)
}
}
what are your thoughts on this topic?damian
02/02/2018, 8:20 AMR?
instead of Unit
so we can use it like a let
for multiple types. (with multiLet(a,b) { a, b -> done } ?: somethingElse
gildor
02/02/2018, 8:38 AMfun solution_destructure() {
val person = moduleExternal()
val name = person.name ?: return
val age = person.age ?: return
safeCall(name, age)
}
Also it allows easily replace return
with error()
or some other null handlerifNotNull
works too, especially for cases where you want to receive result of expression, not just early return
or break
damian
02/02/2018, 8:43 AM?:
approach with exceptions to pass the error futher down and handle it correctly / display a message why it didn’t work. i like it for this case - if you need to know which value exactly is null for examplegildor
02/02/2018, 8:48 AMuhe
02/02/2018, 9:11 AMifNotNull