4

I want to add to the list objects only if they have all fields, and try this code:

data class Response(val id: String, val name: String)
val list = mutableListOf<Response>()

val id : String? = "test_id"
val name : String? = "test_name"

if (!id.isNullOrBlank() and !name.isNullOrBlank()) {
    list.add(Response(id, name)) // Type mismatch. Required String, Found String?
}

But I got an error: Type mismatch. Required String, Found String? What is the correct (and compact) way to do it?

anber
  • 3,463
  • 6
  • 39
  • 68
  • 1
    `and` does a bitwise AND, use `&&` – Tim Dec 18 '18 at 09:09
  • @TimCastelijns thanks it works. But, why in this case Kotlin allows `and`, `or` as logical operators between boolean? – anber Dec 18 '18 at 09:26
  • because the stdlib defines `public infix fun and(other: Boolean): Boolean` for Boolean instances – Tim Dec 18 '18 at 09:30
  • @TimCastelijns than I'm puzzled - in javadoc it says: `Performs a logical 'and' operation between this Boolean and the [other] one. Unlike the `&&` operator, this function does not perform short-circuit evaluation.`. So it should be an equivalent of java single & operator, and should work, but it does not? – anber Dec 18 '18 at 09:40
  • *So it should be an equivalent of java single & operator, and should work,* - yes, but why should that work? – Tim Dec 18 '18 at 09:47
  • @TimCastelijns from my point of view `&&` and `and` operators have the same logical result, but in 1 case smart cast works, and in 2 does not – anber Dec 18 '18 at 09:50
  • while I do not really have an answer to the bitwise `and` not giving the same result, I can only recommend to always use `&&` instead of bitwise `and` due to the short-circuiting.... (if you have a use-case where all functions within a condition must be called (regardless of the outcome), then of course bitwise `and` might be more appropriate... but usually one doesn't need such constructs)... – Roland Dec 18 '18 at 10:10
  • 3
    I think this is a good candidate for a Kotlin issue. It should work. – Marko Topolnik Dec 18 '18 at 10:16
  • @MarkoTopolnik I have added an issue https://youtrack.jetbrains.net/issue/KT-28889 – anber Dec 18 '18 at 10:35

2 Answers2

4

As a recommendation: always try to use && instead of bitwise and to evaluate your conditions. Seldomly is there any reason to use a bitwise and (there are some use-cases, but in most cases you just want to have a short-circuiting evaluation of your conditions, even more so if there is some complex calculation/service calls within one of the functions).

From what I see and expect the smart cast should work, even more so because && already does work. I didn't find any appropriate or matching issue, so you may want to open a new ticket for this.

Note also that the smart cast should work due to the Kotlin contract defined in isNullOrBlank which basically checks whether the value underneath is null so it might be related to the evaluation of the contracts, and/or the inlining of the function and/or something of the former combined with the bitwise and.

Roland
  • 22,259
  • 4
  • 57
  • 84
0

An alternative approach I usually like to do, without involving smart casts:

val id : String = getId()?.takeIf { it.isNotBlank() } ?: return
val name : String = getName()?.takeIf { it.isNotBlank() } ?: return
list.add(Response(id, name))

Here you verify the value while you get it and abort if you cannot use it.

tynn
  • 38,113
  • 8
  • 108
  • 143
  • Sorry, but looks like this is not true, looks at comments under the question – anber Dec 18 '18 at 10:06
  • 4
    @tynn you might want to read [Kotlin contracts](https://github.com/Kotlin/KEEP/blob/master/proposals/kotlin-contracts.md)... `isNullOrBlank` has a contract in it and the compiler can do a smart cast... but only if `&&` is used... on a bitwise `and` it doesn't work... and to be honest: you may want to read about smart casts... I find your code is harder to read then the short-circuiting variant with smart cast... – Roland Dec 18 '18 at 10:08
  • @Roland thanks for the link. I actually missed the contracts in _Kotlin_. I guess the code readability is a matter of taste. I find it nicer to read. Please consider providing an answer from your comment as well. – tynn Dec 18 '18 at 10:18