I’m wondering why the if statement doesn’t expect ...
# announcements
m
I’m wondering why the if statement doesn’t expect a nullable Boolean type. What would be the disadvantage of allowing it? Consider this:
Copy code
if (foo?.isNotEmpty() ?: false) { … }
That works, but it’s not really concise. Wouldn’t it be better (and safe) if we could just write
Copy code
if (foo?.isNotEmpty()) { … }
👍 1
🚫 3
s
how is autocasting
null
to
false
safer and better? (and if you have an answer, you won't find many (relatively spoken) who aggree with you in this chat.)
👍 2
c
in your example:
if (!foo.isNullOrEmpty()) {}
m
@christophsturm Yes, that works well for Strings, but not so much for generic conditions. I suppose I could always write my own extension function to hide away the elvis operator. 🙂
(Just like isNullOrEmpty does)
c
in the end you don’t want to arrive in a situation where a flag is either null or false or true.
m
That’s where I am sometimes. The best solution is of course to avoid the nullable type in the first place.
c
i think one of the most common usecases are optional strings and there isNullOrEmpty helps.
and for optional boolean values you will probably assign a default value with the elvis operator at first use
m
Ok, it was a bad idea. Blame it on Friday! 🙂
r
optional booleans are almost never a good idea non-optional booleans with default value replace them in 90% of cases at least and if someone says "But I need 3 diff values!" then it's not a fucking boolean then! Get an enum or your some of own class instead. Sadly I see this often in production code, with comments like
false means A happened, true means B happened, null means OK
Anyways, enum or replacing with default value at earliest possibility / handling it somehow else (example sometimes return from function can be a solution).
💯 1
also if you need to check smth on a nullable variable sometimes
if(foo != null && foo.isNotEmpty())
might be more readable than default value. Ofc, only works on local variables/args...
m
Yes, that’s kind of the “java way” of doing it. Works well for short variable names, otherwise the expression gets kind of lengthy. In that case I’d rather go elvis 🙂
r
yeah, it depends on the expresion, that's why "sometimes"
but if the expression is long enough, I would just assign the boolean result to variable (so it can get name)
m
Now I’m wondering why the isNotEmpty function doesn’t accept a null receiver. I guess it’s because these things are meant to be made explicit in Kotlin
Perhaps something like
CharSequence?.isNeitherNullNorEmpty()
would be nice - it’s verbose, but it seems to be the Kotlin way.
👍 1
It would be nice to have smart casting support when using these functions, at least if they’re inline.
r
(that's what contracts are for no?)
n
You could have an extension for booleans themselves
Instead of trying to add an extension for every specific case
r
Copy code
@OptIn(ExperimentalContracts::class)
fun CharSequence?.isNotNullOrEmpty(): Boolean {
    contract { 
        returns(true) implies (this@isNotNullOrEmpty != null)
    }
    
    return this != null && this.isNotEmpty()
}

fun bar(foo: String?) =
    if (foo.isNotNullOrEmpty()) foo + "bar" else null
this works
ah wait, plus is nullabe, smth else
m
Haven’t looked into contracts yet … interesting!
n
Then you could write foo?.isBar().isTrue()
r
anyways, smth like that should work, I'm not too knowledgable of them either 😛
n
Or if you want to be more explicit, isTrueAndNotNull
But I think isTrue is good enough given the type signature
But maybe that's not enough improvement over ?: false
m
Contract works in this case, but it’s experimental …
i
Is
.isTrue()
significantly better than
== true
?
e
yeah I was going to say, I thought Kotlin style was
== true
over
?: false
n
Ah right, I actually forgot that == works on nullables
kind of silly
c
nice! i always thought
== true
is a noop but thats only true for non nullable booleans
n
I think, to be honest, you could make an argument that if something works with == true, it should just work directly as the condition
1
I wouldn't really consider this "truthiness" or "autocasting", IMHO
r
yes you could, but I still think you should get kicked in face by your IDE, "Care this is nullable!" and whenever to handle it with
?:
or
==
it's whatever, but it should be explicit
n
I dunno,
== true
is not terribly explicit to me
when I look at
if (<expression>)
and
if (<expression> == true)
I'd expect them to be the same
e
is
== true
or
!= false
the right choice? they have different behavior on null
o
It is explicit (when compared to ?: false), because you're explicitly specifying the value you are interested in.
n
but
if
already does that
the value you're interested in is
true
e
is it?
in many languages it's just looking for a "truthy" thing
n
truthiness would make the range of acceptable things in
if
broader
in python there are things that you can't
== True
(or maybe you can but they return False)
But they will "count" as True inside an if
What we're talking about here is that Kotlin's if is actually even narrower than
== true
e
== true
in C, Perl, Python, Ruby, JS etc. changes what an
if
will do
r
(that's true here too, tho)
e
it doesn't in Java and Kotlin, because they require a strict boolean
n
It does, because == true can make something compile
that didn't
as we have just seen 🙂
e
not compiling doesn't change behavior, there was none before
n
different definitions of change behavior
e
do I need to explicitly say, changes runtime behavior?
r
imho, going from "no behavior" to "some" is a change
n
Do I need to say, explicitly changes program behavior?
e
what else matters
n
etc, this is poitnless
Anyway, the point is that it's pretty unusual for an if not to compile with an expression, but to compile with == true. You can force it to happen in languages that allow overloading operator==, but it would be considered a crazy thing to do
1
Actually, interestingly Swift does exactly the same thing 🙂 So perhaps, not that unusual in the context of languages with nullable types
o
That's like saying "It's unusual
if(Char)
doesn't compile but `if(Char == 'a')`", no? With nullable Boolean you're no longer dealing with "standard bool", but you're comparing two values that might as well be random.
n
It's not like that example at all, no, because the value on the right is not
true
I guess what it boils down to, which is pretty unique to languages with null baked into the type system, is that there's a type above boolean
o
But with null in the mix "the value on the right is not `true`" no longer makes sense
You're testing if something is exactly
true
- but please forget about the special treatment of primitive boolean. It's been lifted, promoted to a 3-way value. In that sense it's no different from any other
equals
comparison.
m
@Nir consider that == is different from === in Kotlin.
n
@okarm I'm not sure what you mean by that
o
I guess what it boils down to, which is pretty unique to languages with null baked into the type system, is that there's a type above boolean
This
n
yep
Basically you need some form of implicit conversion in a language for this to work
Either that, or special == between different types
In this case, it's basically the implicit conversion of a type to its supertype (in this case, the nullable version of its own type)
@Michael Böiers that's not really relevant here tbh
m
@Nir No, it’s not. Nevermind. 🙂
🙂 1