Pacane
11/05/2020, 2:59 PMval a: String? = ...
val b: String? = ...
if (listOf(a,b).any { it == null }) {
return
}
val l = a.length // compiler complains here
Basically I'm doing null checks in for a bunch of variables before doing something with them. Shouldn't the compiler know about a
on the last line, not being null?diesieben07
11/05/2020, 3:02 PMMarc Knaup
11/05/2020, 3:06 PMval
s, they cannot change.
The problem here is that the null
check is way too complex for the compiler to understand.Vampire
11/05/2020, 3:07 PMval
is changed by anything, isn't it?
The problem is, that the compiler is not that smart to see the connection between the elements you added to the list being all null-checked.
If you would do if (a == null || b == null) { return }
the smart-casting is done just fine.Pacane
11/05/2020, 3:07 PMchermenin
11/05/2020, 3:08 PMval a: String = … ?: return
?Pacane
11/05/2020, 3:08 PMMarc Knaup
11/05/2020, 3:08 PMif (a == null || b == null) return
b) a?.let { b?.let { your code } }
Pacane
11/05/2020, 3:08 PMMarc Knaup
11/05/2020, 3:09 PMbezrukov
11/05/2020, 3:09 PM?:
in assignment
val a = ... ?: return
val b = ... ?: return
val l = a.length
Pacane
11/05/2020, 3:09 PMPacane
11/05/2020, 3:10 PMPacane
11/05/2020, 3:10 PMPacane
11/05/2020, 3:10 PMDavide Bertola
11/05/2020, 3:10 PMPacane
11/05/2020, 3:11 PMMarc Knaup
11/05/2020, 3:11 PMPacane
11/05/2020, 3:11 PMstreetsofboston
11/05/2020, 3:14 PMlet
or guard
functions. E.g.
inline fun <A: Any, B: Any, R> let(a: A?, b: B?, block: (A, B) -> R): R {
return if (a != null && b != null) block(a, b) else null
}
// overload this one for three params, 4 params, 5 params, etc, as much as you need)
Pacane
11/05/2020, 3:15 PMPacane
11/05/2020, 3:15 PMvar site = parsed.tags["site"]
val asset = parsed.tags["asset"]
val field = parsed.fields.first().fieldKey
val value = parsed.fields.first().fieldValue
if (site == null || asset == null || field == null || value == null) {
continue
}
Pacane
11/05/2020, 3:16 PMMarc Knaup
11/05/2020, 3:16 PM@OptIn(ExperimentalContracts::class)
inline fun anyNull(a: Any?, b: Any?, c: Any?): Boolean {
contract {
returns(false) implies (a != null && b != null && c != null)
}
return a == null || b == null || c == null
}
Usage:
if (anyNull(a, b, c)) return
Pacane
11/05/2020, 3:16 PMPacane
11/05/2020, 3:16 PMfun<T> List<T>.anyNull() = this.any { it == null }
fun List<String?>.anyNullOrEmpty() = this.any { it.isNullOrEmpty() }
Marc Knaup
11/05/2020, 3:16 PM?: return
approach?Pacane
11/05/2020, 3:17 PMPacane
11/05/2020, 3:17 PMDavide Bertola
11/05/2020, 3:17 PMv.takeIf { it.notEmpty() } ?: return null
Marc Knaup
11/05/2020, 3:17 PMdiesieben07
11/05/2020, 3:18 PMval foo: Int get() = Random.nextInt()
Tada, your val is changing.Marc Knaup
11/05/2020, 3:19 PM@OptIn(ExperimentalContracts::class)
inline fun anyNullOrEmpty(a: String?, b: String?, c: String?): Boolean {
contract {
returns(false) implies (a != null && b != null && c != null)
}
return a == null || b == null || c == null || a.isEmpty() || b.isEmpty() || c.isEmpty()
}
Marc Knaup
11/05/2020, 3:19 PMval
s 🤔
But delegation may be an issue.diesieben07
11/05/2020, 3:20 PMVampire
11/05/2020, 3:23 PMVampire
11/05/2020, 3:23 PMgetter
smart casting does not work anywayVampire
11/05/2020, 3:24 PMNir
11/05/2020, 3:51 PMPacane
11/05/2020, 3:52 PMNir
11/05/2020, 3:52 PMMarc Knaup
11/05/2020, 3:52 PMPacane
11/05/2020, 3:53 PMNir
11/05/2020, 3:53 PMPacane
11/05/2020, 3:53 PMPacane
11/05/2020, 3:53 PMMarc Knaup
11/05/2020, 3:53 PMMarc Knaup
11/05/2020, 3:54 PMPacane
11/05/2020, 3:54 PMPacane
11/05/2020, 3:54 PMNir
11/05/2020, 3:55 PMNir
11/05/2020, 3:56 PMNir
11/05/2020, 3:58 PMPacane
11/05/2020, 3:59 PM