Kotlin: Cannot apply two conditionals at once check with "return body" function style - kotlin

I have a simply function check like this:
fun parseValidBluetoothBrickedId(controllerId: String?): Boolean{
if(controllerId != null){
if(controllerId.startsWith(BLUETOOTH_NAME_PREFIX) && controllerId.length > BLUETOOTH_NAME_PREFIX.length)
return true
}
return false
}
I want to convert it to simplier style:
fun parseValidBluetoothBrickedId(controllerId: String?) =
controllerId?.length > BLUETOOTH_NAME_PREFIX.length
&& controllerId?.startsWith(BLUETOOTH_NAME_PREFIX)
but IDE(Android Studio 3.0 Beta7) gives me an error, underlines the greater than('>') operator:
Operator calls corresponds to a dot-qualified call 'controllerId?.length.compareTo(BLUETOOTH_NAME_PREFIX.length) which is not allowed here
Also it underline as an error line controllerId?.startsWith(BLUETOOTH_NAME_PREFIX) and says:
Type mismatch. Required: Boolean, Found Boolean?
What is the problem, really? It is just a simply method, works well with the first block if-else style.

You can't call compareTo (use the < operator) on controllerId?.length, since its type is Int?, which means it might be null, in which case it can't be compared as a number.
Similarly, the controllerId?.startsWith(BLUETOOTH_NAME_PREFIX) call returns Boolean? (since it will return null if controllerId is null), which can't be passed to the the && operator, only a real Boolean can.
The solution here is to do the null check that you were doing in your original method, and get rid of the safe calls by relying on smart casts casting your controllerId to String:
fun parseValidBluetoothBrickedId(controllerId: String?): Boolean =
controllerId != null
&& controllerId.length > BLUETOOTH_NAME_PREFIX.length
&& controllerId.startsWith(BLUETOOTH_NAME_PREFIX)

When you do controllerId?.length, you are getting an Int?. You cannot compare Int with an Int?. That is the reason you get the first error.
You get the other error because controllerId?.startsWith(BLUETOOTH_NAME_PREFIX) returns Boolean?. You cannot use the && operator on a nullable parameter. It requires two parameters of type Boolean.
To solve the problems, you need to check controllerId != null first. This will smart cast controllerId to the non-nullable type String. Like this:
fun parseValidBluetoothBrickedId(controllerId: String?): Boolean =
controllerId != null
&& controllerId.startsWith(BLUETOOTH_NAME_PREFIX)
&& controllerId.length > BLUETOOTH_NAME_PREFIX.length

Your transformed function is missing the null check:
fun parseValidBluetoothBrickedId(controllerId: String?) =
controllerId != null && controllerId.length > "".length
&& controllerId.startsWith("")
As in your first example, the null check is necessary for the compiler to know, that controllerId is not null. After the check, the compiler uses "smart casting" and the calls are safe.
Therefore you do not have to use ?. notation after the check.

Related

Kotlin idiom: null-safe conditional?

In Java, I'd write something like this:
if (foo != null && foo.bar()) { ...
However Kotlin complains that:
Smart cast to 'Foo' is impossible, because 'foo' is a mutable property that could have been changed by this time
I think it's saying what I wrote isn't thread-safe. However, in the context where I'm using it I know it is as this will always be invoked on a single thread.
Yes foo needs to be mutable. I realize that making foo a val would solve this but that is not possible here.
What's the correct idiom in Kotlin to handle this case?
In this case, a null-safe call returns a Boolean? so you can check if it equals true:
if (foo?.bar() == true) {
}
If you need non-null foo inside the conditional, then you can use the common ?.let idiom.
foo?.let { foo ->
if (foo.bar()) {
}
}
If you know it’s only accessed on this same thread, the !! operator would be safe after the null check, but ?.let is more idiomatic so easier to follow once you’re used to reading Kotlin.
The trick is to use Kotlin's excellent null-safety operators to avoid having to do redundant checks.
First, we use the safe-call operator.
foo?.bar()
This is a Boolean? (i.e. a nullable Boolean) which is null if foo is null, or the result of bar() if not. Now, a Boolean? is not a valid condition in an if statement, obviously, so we need to provide a "default" value of false. We do that using the amusingly-named Elvis operator
if (foo?.bar() ?: false) { ... }
If foo is null, then foo?.bar() is null, and ?: returns the value of the right-hand side, i.e. false. If foo is non-null, then foo?.bar() is the result of calling bar() on foo, and (assuming that result is also non-null), ?: returns the existing non-null Boolean value.
In case where the condition is not just a function call, e.g.
foo != null && foo.bar() > 0
you can use let or run:
if (foo.let { it != null && it.bar() > 0 }) { ... }
if (foo.run { this != null && bar() > 0 }) { ... }

How to use equals() and contains() to check nullable type of data? I suppose they are both string's methods, but why they behave differently?

CASE 1: it can compile and run. why no exception when null call equals() ?
var myStr:String? = null
if (myStr.equals("hello"))
println("equals hello")
else
println("not equals hello")
CASE 2: it cannot compile. I suppose it is similar to the above case, but I am wrong. Why?
var myStr:String? = null
if (myStr.contains("hello"))
println("contains hello")
else
println("not contains hello")
equals function is defined as extension function on nullable String reference String?, while contains method is defined on non-nullable CharSequence.
public actual fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean = ...
public operator fun CharSequence.contains(other: CharSequence, ignoreCase: Boolean = false): Boolean = ...
In both cases myStr is nullable String, so you cannot call contains directly. You can use null safety operator ?. for calling contains
if(myStr?.contains("hello") == true)
println("contains hello")
else
println("not contains hello")
PS: In case of equality check, you don't need to use equals method, instead you can just use == operator
equals on a nullable string works, only because it is a very special case. There is an equals specifically written for String?.
fun String?.equals(
other: String?,
ignoreCase: Boolean = false
): Boolean
This wouldn't work on Int?, for example:
var i: Int? = null
if (i.equals(1)) // error here
println("equals 1")
else
println("not equals 1")
The equals function is declared for Any, not Any?, so you can't call it on nullable types in general.
Anyway, the idiomatic way to compare equality is to use a == b, which translates to a?.equals(b) ?: (b === null) for a nullable a.
There is also no reason to allow myStr.contains("hello") to compile, since contains is declared on the non-nullable CharSequence.
operator fun CharSequence.contains(
other: CharSequence,
ignoreCase: Boolean = false
): Boolean
You can check it like this instead, with nullable chaining:
if (myStr?.contains("hello") == true)
In the first example, myStr.equals calls the String?.equals extension function, which does the following:
if (this === null)
return other === null
In your case, this is null, and other is not null, so other === null produces false.
In the second example, myStr.contains("hello") is trying to call a function called contains, but it doesn't exist, because you have a nullable String?, and there is no contains function defined for that type. There is the CharSequence.contains function, but that is only defined for non-nullable types.
So because the function doesn't exist, you get a compiler error.
Generally, you don't need to use the equals function anyway, and should prefer the == operator:
val myStr:String? = null
if (myStr == "hello")
println("equals hello")
else
println("not equals hello")
For contains, you can use the ?. operator to ensure the object on the left is not null first:
val myStr:String? = null
if (myStr?.contains("hello") == true)
println("contains hello")
else
println("not contains hello")
Here, myStr?.contains("hello") produces null, and null == true is false, so the result is false.

Is it necessary to check null when use 'is' operator

I have an instance which can be null. Fox example
var str: String? = null
So I need to check if str is String. Do I need to check for null if I use the is operator.
First option:
if(str is String) {}
Second option:
if(str != null && str is String) {}
Please help me which way is better to use ?
The is operator is safe and returns false in the case you supply a null instance
https://pl.kotl.in/HIECwc4Av
Somewhere, you HAVE to nullcheck.
Kotlin provides many ways to enforce non-null:
Use a non-null type:
var nonNull : String = ""
var nullable : String? = "" // notice the ?
nullable = null // works fine!
nonNull = null // compiler error
and if you encounter a nullable type, you can use let {} ?: run {} construct to unwrap it and execute your code with a non-nullable:
nullable?.let { // use "it" to access the now non-null value
print(it)
} ?: run { // else
print("I am null! Big Sad!")
}
Kotlin strictly distinguishes between nullable T? and nonnull T.
Use T wherever possible to avoid null checks.

Not nullable value required to call 'component1()' function of destructuring declaration initializer

Is it possible to make the following code to compile in Kotlin?
val variable: String? = "string"
val (a, b) = variable?.run {
1 to 2
}
The compiler does not allow destructuring because the expression on the right-hand side is typed as a nullable Pair<Int, Int>?, and it's unclear what values a and b should get in case variable is null.
To solve this, you need to get a not-null expression after =.
There's a lot of different ways to deal with nullable values and produce a not-null value from a nullable one, see: In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them
For example, if you want to provide fallback values for a and b, then use the ?: operator as follows:
val (a, b) = variable?.run {
1 to 2
} ?: (0 to 0)
An alternative, for example, would be to check variable for null first:
val (a, b) = checkNotNull(variable) { "variable should never be null" }.run {
1 to 2
}
Null doesn't have any destructuring declarations. If you want a value of null to destructure like it's a pair of nulls, you could add these extensions:
operator fun <T> Pair<T, *>?.component1() = this?.component1()
operator fun <T> Pair<*, T>?.component2() = this?.component2()
Otherwise, as the other answer shows, you need to provide a default using the Elvis operator.
It's not automatic because it doesn't know what you want. Depending on what you're doing with it, 0 to 0 may be most appropriate, or maybe -1 to -1 or 0 to null or null to null.
The question is, what do you want to do if your variable is null? If you want to throw an exception, go with require or check as #hotkey suggested.
However I have the case where I just want to return if the value is null. So I wrote myself a little helper function that allows for this:
private inline fun <T> T?.exitIfNull(exitBlock: () -> Nothing): T {
if (this == null)
exitBlock()
else
return this
}
You can call this function as follows:
val (a, b) = variable?.run {
1 to 2
}.exitIfNull {
return
}
A nice little use of the Nothing keyword in Kotlin that I personally find quite fascinating

What does ?: do in Kotlin? (Elvis Operator)

I can't figure out what ?: does in for example this case
val list = mutableList ?: mutableListOf()
and why can it be modified to this
val list = if (mutableList != null) mutableList else mutableListOf()
TL;DR: If the resulting object reference [first operand] is not null, it is returned. Otherwise the value of the second operand (which may be null) is returned. Additionally, the operator can throw an exception if null is returned.
The Elvis operator is part of many programming languages, e.g. Kotlin but also Groovy or C#.
I find the Wikipedia definition pretty accurate:
In certain computer programming languages, the Elvis operator ?: is a binary operator that returns its first operand if that operand is true, and otherwise evaluates and returns its second operand. It is a variant of the ternary conditional operator, ? :, found in those languages (and many others): the Elvis operator is the ternary operator with its second operand omitted.
The following is especially true for Kotlin:
Some computer programming languages have different semantics for this operator. Instead of the first operand having to result in a boolean, it must result in an object reference. If the resulting object reference is not null, it is returned. Otherwise the value of the second operand (which may be null) is returned. If the second operand is null, the operator is also able to throw an exception.
An example:
x ?: y // yields `x` if `x` is not null, `y` otherwise.
x ?: throw SomeException() // yields `x` if `x` is not null, throws SomeException otherwise
The Elvis Operator is represented by a question mark followed by a colon: ?: and it can be used with this syntax:
first operand ?: second operand
It enables you to write a consise code, and works as such:
If first operand isn't null, then it will be returned. If it is null, then the second operand will be returned. This can be used to guarantee that an expression won't return a null value, as you'll provide a non-nullable value if the provided value is null.
For example(in Kotlin):
fun retrieveString(): String { //Notice that this type isn't nullable
val nullableVariable: String? = getPotentialNull() //This variable may be null
return nullableVariable ?: "Secondary Not-Null String"
}
In this case, if the computed value of getPotentialNull is not null, it will be returned by retrieveString; If it is null, the second expression "Secondary Not-Null String" will be returned instead.
Also note that the right-hand side expression is evaluated only if the left-hand side is null.
In Kotlin, you could use any expression as second operand, such as a throw Exception expression
return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")
The name Elvis Operator comes from the famous American singer Elvis Presley. His hairstyle resembles a Question Mark
Source: Wojda, I. Moskala, M. Android Development with Kotlin. 2017. Packt Publishing
This is called the Elvis operator and it does... Exactly what you've described in your question. If its left hand side is a null value, it returns the right side instead, sort of as a fallback. Otherwise it just returns the value on the left hand side.
a ?: b is just shorthand for if (a != null) a else b.
Some more examples with types:
val x: String? = "foo"
val y: String = x ?: "bar" // "foo", because x was non-null
val a: String? = null
val b: String = a ?: "bar" // "bar", because a was null
Let's take a look at the defintion:
When we have a nullable reference r, we can say "if r is not null, use
it, otherwise use some non-null value x":
The ?: (Elvis) operator avoids verbosity and makes your code really concise.
For example, a lot of collection extension functions return null as fallback.
listOf(1, 2, 3).firstOrNull { it == 4 } ?: throw IllegalStateException("Ups")
?: gives you a way to handle the fallback case elgantely even if you have multiple layers of fallback. If so, you can simply chain multiply Elvis operators, like here:
val l = listOf(1, 2, 3)
val x = l.firstOrNull { it == 4 } ?: l.firstOrNull { it == 5 } ?: throw IllegalStateException("Ups")
If you would express the same with if else it would be a lot more code which is harder to read.
The elvis operator in Kotlin is used for null safety.
x = a ?: b
In the above code, x will be assigned the value of a if a is not null and b if a is null.
The equivalent kotlin code without using the elvis operator is below:
x = if(a == null) b else a
Simply we can say that, you have two hands. You want to know, is your left hand working right now?. If left hand not working, return empty else busy
Example for Java:
private int a;
if(a != null){
println("a is not null, Value is: "+a)
}
else{
println("a is null")
}
Example for Kotlin:
val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"
Consider below example,
var myStr:String? = null
//trying to find out length of myStr, but it could be null, so a null check can be put as,
val len = if (myStr != null){
myStr.length
}
else{
-1
}
Using the elvis operator, the above code can be written in a single line
val len = myStr?.length ?: -1 // will return -1 if myStr is null else will return length
In addition to what has been already stated there is one good pattern that was not obvious for me, but which is common, e.g. you're writing a long function, but if something is null there is no sense to continue and the only thing you can do is to return from the function. Normally you'd write
something = expression
if (something == null) {
return
}
With elvis it becomes shorter and more elegant:
something = expression ?: return
Basically, if the left side of Elvis returns null for some reason, returns the right side instead.
i.e.
val number: Int? = null
println(number ?: "Number is null")
So, if number is NOT null, it will print number, otherwise will print "Number is null".
A little addition though is this
X = A ?: B
X will still be null if both A and B evaluate to null
Therefore, if you want X to always be non-null, make sure B is always a non-null or that B always evaluates to non-null if it's a function or expression.