Kotlin: check if a nullable value is valid in an if statement - kotlin

Ideally, I think the commented-out if statements make more sense, at least to me. I mean, if someone asks me if null is bigger than 0, than I would answer no. Or if null is true, then also no. But those did not work as I expected, and throw compilation errors. So, I have changed those like below. But those do not look good or concise. Is there a better way to handle these?
class Result(val code:Int)
{
}
fun getResult():Result?
{
return null;
}
fun main(args: Array<String>)
{
var result = getResult();
var success:Boolean? = null;
//if(result?.code > 0)
if(result?.code?:0 > 0)
{
print("Good.");
}
//if(success)
if(success == true)
{
print("Good.");
}
}

The > is compiled to a call of compareTo(other: Int), which works by convention (its defined as an operator on Int). You cannot invoke this function on nullable Int? though.
There'd be a workaround: Create another extension on Int?:
operator fun Int?.compareTo(other: Int): Int =
(this ?: 0).compareTo(other)
Now your call does work:
if (result?.code > 0)
print("Good.")

the nullable element is actually the Result instance itself, not its code property.
i think using let in combination with the safe-get operator on the result more accurately reflects the design of the code:
result?.let {
if(it.code > 0) {
}
}

The reason the commented-out code did not compile is because result?.code is nullable and you can't call comparing operator (i.e > in this case) on a nullable expression because they don't type match. (it is defined to only accept non-nullable types)
if null is bigger than 0, than I would answer no. Or if null is true, then also no
Kotlin completely disambiguates between nullable and non-nullable entity. So, at compile time kotlin compiler refuses to compile if you are comparing something with a nullable type, to avoid run time exception ahead of time. In java,
Integer x = null;
System.out.println(x > `)
this compiles but throws a NullPointerException on runtime, which you obviously do not want. Kotlin compiler is just being smart here to avoid such runtime exceptions by refusing to compile.
Now onto the better way to deal with it, like everyone said, using let is an appropriate way. A simpler way can be a regular null check with if expresion
if(result != null && result.code > 0) {
print("Good.");
}

result?.code > 0
It's not working because > internally calls compareTo() method. compareTo() method does not work on a nullable object. That's why you have to add elvis operator(?:) on variable code to assign a value if the code variable is null. So that the value is not null and then compareTo() method works.
result?.code?:0 > 0
I have added a let to solve. If the result is not null then we will execute the code within the let block. Please check the updated code.
class Result(val code:Int){
}
fun getResult():Result?{
return null;
}
fun main(args: Array<String>){
var result = getResult();
var success:Boolean? = null;
//if(result?.code > 0)
if(result?.code?:0 > 0){
print("Good.");
}
// Updated Code
result?.let{
if(result.code > 0)
print("Good.")
}
//if(success)
if(success == true){
print("Good.");
}
}

Related

Kotlin multiple variable let, using the previous variables in the next let

I want to be able to have multiple let and the next let is able to use the previous variable only if its not null. The reason I want this is because I want only one :? for all the lets. Is this possible?
Example on how I want it to be:
fun example() {
firstVariable?.let a -> &&
exampleFunction(a, 3)?.let { a, b ->
// Use a and b freely since they are not null and not optionals
} ?: run {
// Runs if either one of the let is failing
}
}
// a is NOT optional
fun exampleFunction(a: Int, b: Int?): Int? {
if (b == null) {
return null
}
return a + b
}
Stupid example, but its just to show what I need... I want to check if the first variable is null AND to run a function that returns an optional with a non-optional parameter which is the first variable - if either of these fail, I want to run something else.
I know how to do this without let, but I am wondering if it's possible or planned to be able to do this? (It's possible in Swift).
How to do it in Swift:
// First check a, then use a in the same expression if its validated
if let a = firstVariable,
let b = exampleFunction(a) {
// Use a and b as non-optionals
} else {
// a or b failed
}
You propably missunderstood how let works. I am going to explain a bit. In short the desired behaviour is not possible in kotlin or at least you can not idiomatically emulate it without any drawbacks whatsoever.
I don't know swift but it seems as if the let used there is some sort of syntax construct offered by the language itself. It allows you to define a variable with some local scope and can be chained (like the short circuiting &&).
In Kotlin however let is just a normal function.
See the documentation. It's basically nothing more than
fun <T, R> T.let(block: (T) -> R): R = block(this)
It allows to call a function with a normal parameter as a function with a receiver type.
The actual null check is done with the ?. operator.
It takes an optional/nullable value as left hand side operand and either short circuits returning null or call the function on the right hand side with the non-null left hand side as receiver type. let is just one possible function to call here.
The similar ?: operator takes an optional/nullable LHS operand and returns this value if it is not null or it evaluates the expression on the RHS.
One way to get those variables defined is by nesting lets:
firstVariable?.let{a -> exampleFunction(a, 3)?.let{b -> a + b}} ?: run{}
where a + b is just an example of using both values. This however becomes unhandy if it's longer than one line. If you still want to define local variables you can create a block with run and use jump statements on the right side of ?:
run {
val a = firstValue ?: return#run null
val b = exampleFunction(a, 3) ?: return#run null
return#run a + b
} ?: run{}
While the above code looks really ugly with all those return#run null repititions there might be ways to reduce the amount of repeating code e.g. by using a anonymous function (to get rid of the #run part) or return Unit and safe the last value with some side-effect operation. (to get rid of the null and the last return statement)
You could benefit on Kotlin and write sot of extension function for your case. vararg as we dont know how many variables we want to pass, then check if all of them are not null and if so, return all of them. If any of the vars will be null, then nothing happens.
fun <T: Any> multipleLetCheck(vararg variables: T?, block: (List<T>) -> Unit): Unit? {
return if (variables.all { variable -> variable != null }) {
block(variables.filterNotNull())
} else {
null
}
}
// usage
multipleLetCheck(firstVariable, 3){ (firstVariable, secondVariable) ->
// work with firstVariable and secondVariable
} ?: run {
}

Is there an elegant kotlin way of convincing the compiler that a nullable field to which I just assigned a real value can't be null anymore?

I have read that using !! should generally be avoided.
Is there a way to write the following code in a more elegant way without having to add something like obsolete null checks and duplicated or dead blocks of code?
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
return field!!
}
}
Also I don't understand why the compiler requires the !!-'pray-this-isn't-null-operator' to be satisfied in this scenario.
EDIT: Consider that it is important to me that a potential solution uses lazy initialization if the field is null!
Problem
As Enzokie already mentioned in the comments, another thread could have changed field after the null check. The compiler has no way of knowing that, so you have to tell it.
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
// another thread could have assigned null to field
return field!! // tell the compiler: I am sure that did not happen
}
}
Solution (Eager)
In you particular case it would be a good idea to use a parameter f (you could name it "field" too, but I avoided that for clarity) in the constructor (without val/var) and afterwards assign it to a property field to which you assign either f or a new instance of Thing.
This can be expressed really concise with the Elvis operator :? which takes the left hand side if not null and the right hand side of the expression otherwise. So, in the end field will be of type Thing.
class A(f: Thing?) {
val field = f ?: Thing() // inferred type Thing
}
Solution (Lazy)
Since it was mentioned by gidds, if you need to initialize field lazyly you could do it like this using delegated properties:
class A(f: Thing?) {
val field by lazy {
f ?: Thing() // inferred type Thing
}
}
The call site does not change:
val a = A(null) // field won't be initialized after this line...
a.field // ... but after this
How about this?
class A(field: Thing?) {
private lateinit var field: Thing
init {
field?.let { this.field = it }
}
fun getField(): Thing {
if (!this::field.isInitialized) {
field = Thing()
}
return field
}
}
When you define a field, you actually define a variable plus two accessor methods:
val counter: Integer = 0
It is possible to customize the accessor methods by writing this instead:
val n = 0
val counter: Integer
get() = n++
This will execute the n++ each time you access the counter field, which therefore returns different values on each access. It is uncommon and unexpected but technically possible.
Therefore the Kotlin compiler cannot assume that two accesses to the same field return the same value twice. Usually they do, but it is not guaranteed.
To work around this, you can read the field once by copying it into a local variable:
fun count() {
val counter = counter
println("The counter is $counter, and it is still $counter.")
}

Smart casting not working when statement is refactored. How to solve?

I have something simple below (I use when instead of if, as I simplified from some code that uses when)
fun simplePresent(presentable: Presentable?) {
when {
presentable != null -> execute(presentable)
else -> skip()
}
}
fun execute(presentable: Presentable) { // Do something }
It's all good. But when I refactor the checking code out into Function
fun simplePresent(presentable: Presentable?) {
when {
hasPresentable(presentable) -> execute(presentable)
else -> skip()
}
}
fun execute(presentable: Presentable) { // Do something }
fun hasPresentable(presentable: Presentable?) = presentable != null
the smart casting to non-null fail for the value pass to execute function, causing a compile time error reporting required Presentable found Presentable?
How could I prevent that error, while I still retain my refactor code?
Functions are meant to be independent to each other. There is just no constraint to enforce hasPresentable to return true iff presentable is not null at type level.
So it's kind of impossible without Kotlin team deciding to enhance the type system.
Why not using something like presentable?.execute() ?: skip() instead?
If you want to do more checking in hasPresentable you can do this:
fun checkPresentable(presentable: Presentable?): Presentable? =
presentable?.takeIf { do your check here }
fun simplePresent(presentable: Presentable?) =
checkPresentable(presentable)?.execute() ?: skip()
fun Presentable.execute() { }

type inference on empty arrays kotlin

Let's say I have a piece of code like:
fun temp2 (li : MutableList<Int>):Int {
if (li.isEmpty()) return 0
val pos=li.filter { it>0 }
val neg=li.filter { it<0 }
if (pos.isEmpty() && neg.isNotEmpty()){
// this gives compiling error because Required: Int, Found: Int?
// But I just checked one line higher that neg is Not Empty, so there (at least I guess)
// no possible way to have an NPE?
//return neg.max()
return neg.max()!! //this works fine
}
Is there any particular reason why compiler doesn't infer that .max() can only yield an Int, and thus this should not be an error, or am I missing something?
Kotlin's documentation proudly points out about Smart Casts, and I think this is a quite similar and easy inference to make?
That can’t be handled by smart casting, you're using a max() extension function which always returns a nullable type, Int? in your case:
public fun <T : Comparable<T>> Iterable<T>.max(): T?
The compiler does what this method signature suggests: it makes you handle the possible null. How should the compiler know wether max works as intended? It might be implemented wrongly.
The following, on the other hand, works thanks to smart casting:
val maxNeg: Int? = li.filter { it < 0 }.max()
if (maxNeg != null) {
return maxNeg //Can be used as Int
}

How to pass nullable type into function that takes a non null type?

Is this possible if I do a null check before passing? For example:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
I don't understand why the compiler won't allow me to pass a nullable even though I check that it's not null first. Can anyone explain?
NOTE: starting from compiler version 1.0 beta the code in question works as is
The compiler can tell if the variable is mutated between check and use, at least in case of local variables like in this question, and in some other cases. See Jayson's answer for details.
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions says
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
So something like this should work:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
Of course, it would be nicer to rewrite "stuff happens" in such a way that you could make num into a val in the first place.
In current Kotlin (1.0 beta or newer) you do not have this issue anymore. Your code would compile. A local variable that is val or var can safely Smart Cast since the compiler can determine if the value could have mutated or not (on another thread for example).
Here is an excerpt from another Stack Overflow question that covers more aspects of nullability and Kotlin's operators for dealing with them.
More about null Checking and Smart Casts
If you protect access to a nullable type with a null check, the compiler will smart cast the value within the body of the statement to be non nullable. There are some complicated flows where this cannot happen, but for common cases works fine.
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
Or if you do a is check for a non nullable type:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
And the same for 'when' expressions that also safe cast:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
Some things do not allow the null check to smart cast for the later use of the variable. The example above uses a local variable that in no way could have mutated in the flow of the application, whether val or var this variable had no opportunity to mutate into a null. But, in other cases where the compiler cannot guarantee the flow analysis, this would be an error:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
The lifecycle of the variable nullableInt is not completely visible and may be assigned from other threads, the null check cannot be smart cast into a non nullable value. See the "Safe Calls" topic below for a workaround.
Another case that cannot be trusted by a smart cast to not mutate is a val property on an object that has a custom getter. In this case the compiler has no visibility into what mutates the value and therefore you will get an error message:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
read more: Checking for null in conditions
You can use let to simplify the code. The kotlin scope function introduces a local variable in the context of "num". No need to declare temporary variable numVal.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
Which works same as below but simpler and cleaner.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
Use can use Scoping function let or apply along with null safe operator ?.
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
This way you can pass a nullable type to a non-nullable type parameter