Kotlin nullability check if-else functional approach...How? - kotlin

For simple check like
if (variable != null) {
doSomething(variable)
}
We could change to
variable?.let { doSometing(it) }
However for a case with else
if (variable != null) {
doSomething(variable)
} else {
doOtherThing()
}
Is there a way of doing so in a single function? Is there something like either?

You can use the elvis-operator ?: like so:
variable?.let { doSomething(it) } ?: doOtherThing()
However personally I think that this gets quite unreadable very quickly. There is nothing wrong with an if-expression.

Another approach which might ring well with functional style is the use of when, which is very close to pattern matching:
when(variable) {
null -> doOtherThingSomething()
else -> doSomething(variable)
}
I would argue, however, that you should be careful with abandoning the classic if statement, if what you're after is its natural purpose - conditional execution. If you're calculating a value in two different ways and then using it in the same way, this approach makes sense. But if your code paths diverge at this point and don't meet again, then if provides a clearer intent.

You can map null-able value if not null by using ternary operator to check not null condition with If...Else Statements.
Here, I had wrote some code snippet to check value null or not ,
Case 1: value initialized
fun main(args: Array<String>) {
val value:Int ?= 10
val mapped = value?.let { "Value is == $value" } ?: "Value not initialized..."
println(mapped)
}
You gotta result: Value is == 10
Case 2: value set remains null
fun main(args: Array<String>) {
val value:Int ?= null
val mapped = value?.let { "Value is == $value" } ?: "Value not initialized..."
println(mapped)
}
You gotta result: Value not initialized...

Related

Looking for a more idiomatic way to do conditional logging during a list map

There's gotta be a more Kotlin-esque and terse way to do this in Kotlin, but it's not coming to me. Imagine you're doing a mapNotNull operation. Items which cannot be mapped are converted to null to be filtered out. Items that cannot be mapped also result in a warning being printed. This code works, but it's really verbose. Can you help me trim it down?
val listOfStrings = listOf("1","2","3","not an int", "4","5")
val convertedToInts = listOfStrings.mapNotNull {
val converted = it.toIntOrNull()
if(converted == null){
println("warning, cannot convert '$it' to an int")
}
converted
}
I think your code is idiomatic and readable as it is. I prefer to write it with the explicit null-check.
But if you really want to make a shorter one-liner, you could do something like below. But it looks very hacky with the null.apply {} which is needed to return null instead of Unit from the right side of the elvis-operator:
val listOfStrings = listOf("1","2","3","not an int", "4","5")
val convertedToInts: List<Int> = listOfStrings.mapNotNull {
it.toIntOrNull()
?: null.apply { println("warning, cannot convert '$it' to an int") }
}
You could also use run which looks a bit more readable:
?: run {
println("warning, cannot convert '$it' to an int")
null
}

How to make an extension function that prints all datatypes in kotlin?

I want to make an extension function(named (printDatatype) for example) that can be applied on all datatypes and just prints it ... for example :
"example".printDatatype() ==>output: example
56.prinDatatype()==>output: 56
null.printDatatype()==>output: null
className.printDatatype()==> output: ClassName(property1 = value, property2 = value ....)
Soo something like this?
fun Any?.printLn() = println(this)
Any custom objects will need to override the toString method (like always). That will be auto on data classes.
I honestly don't know what the use case for something like would be.
so i figured it out :)
fun Any?.printMe() {
if (this is Class<*>) {
println(this.toString())
} else if (this.toString() == "null"){
println("null")
}
else {
println(this)
}
}

null to listOf(), not null to listOf(value) in Kotlin in one liner?

Let f() return a nullable value.
What I want to do is that
if f() is null, get an empty list,
else if f() is not null, get a list of the single item value.
In Scala, we can do something like this:
Option(f()).toList
or more verbosely
Option(f()).map(v => List(v)).getOrElse(List.empty)
In Kotlin, there is no Option (assuming no Funktionale library), and null does not have toList() unlike (None: Option) in Scala.
We have the Elvis operator, but null will be inside the listOf() function, so it will be
listOf(f() ?: /* What can I do here? */)
What we want for null is listOf(/*no argument */), but the Elvis operator requires an argument, so listOf(f() ?: ) will result in a compile error.
At least we can do
val v = f()
if (v == null) listOf() else listOf(v)
but it is a two liner.
Is there some expression for this?
Where I will use this expression is in the class's primary constructor default argument, so if it is not a one liner, it will be enclosed in brackets, so something like this:
class A(
val p1: List<V> = run {
val v = f()
if (v == null) listOf() else listOf(v)
},
val p2: ... = ...,
...)
This looks pretty ugly, isn't it?
EDIT
As #Naetmul pointed out, listOfNotNull(f()) is syntactically better to what I originally posted below, and also takes a variable number of arguments, for example
val myList = listOfNotNull(f(), g(), h())
will return a list of all the results that were not null.
I would use let here.
val myList = f()?.let { listOf(it) } ?: emptyList()
Use a ?. safe call on the return value of f(), then use let to run a code block. If f() is null, it won't run this block of code, resulting in a null value. Then we use the ?: elvis operator to fall back to an empty list.
Here it is broken up into several lines for a better understanding
val myValue = f()
val myList: List<Any>
if (myValue != null) {
myList = listOf(myValue)
} else {
myList = emptyList()
}
For this specific question, I can do
listOfNotNull(f())

Comparing two optionals in Kotlin

Consider a class with id field which might be null until stored in database:
class IdableK<T : IdableK<T>> : Comparable<T> {
private var id : Long? = null
}
I am trying to implement a compareTo method as follows:
override fun compareTo(other: T): Int {
if (id == null) {
return -1;
}
if (other.id == null) {
return 1;
}
return id!!.compareTo(other.id!!)
}
Is this a correct way of doing it? Would there be a simple way of doing it?
Check out the kotlin.comparisons package. e.g. You can use compareValues:
class IdableK<T : IdableK<T>> : Comparable<T> {
private var id: Long? = null
override fun compareTo(other: T) = compareValues(id, other.id)
}
This is incorrect. If you have two instances with their ids set to null, both instances will return -1 when you call compareTo(other) on them, while if one returns -1 the other should return 1 in a correct implementation. I'm not sure if there are situations where it makes sense to implement compareTo based on nullable properties, but I can't imagine any. Maybe there's a better way for you too?
Also, you should avoid non-null assertions (!!). Since you're using vars, other threads may change the value to null so that even if you did a null check before, the value is now null and !! throws. Instead, you should store both ids in local variables and check these for null values.
If you absolutely have to use compareTo, I'd do it like this:
override fun compareTo(other: T): Int {
val thisId = id
val otherId = other.id
if (thisId == null && otherId == null) return 0
if (thisId == null && otherId != null) return -1
if (thisId != null && otherId == null) return 1
// thisId and otherId are now smart cast to Long
return thisId.compareTo(otherId)
}
Here is a simple way:
override fun compareTo(other: T) :Int {
return id?.compareTo(other.id ?: return 1) ?: -1
}
However this piece of code is very unfriendly to a novice kotlin programmer. It involves too much magic that make it look like scala. These 3 question marks make people puzzled, at least they must think for a minute or two before they could realize what is going on in this minimalistic one-liner. I still prefer your edition. It's more verbose, but clear.
And I'm really worried about the symmetric problem. This matters, and isn't just a design problem. If you don't compare nullable properties, there won't be this programming puzzle. It will just be override fun compareTo(other: T) = id.compareTo(other.id). Simple, clear, and no misleading.
I would rather throw away all null checking code and just live with those null assertions. Because mostly you won't compare there things until it is fully initialized. If these assertion fails, it means something really bad has happens.
Oh, BTW, I don't know about your project, and if it hits the rare cases that you have to compare nullable properties, I think you could write a special edition of Comparator that consider nulls instead of throwing NPEs. Don't mess with the natural order.

How to pattern match optionals in Kotlin?

Is it possible to write something like this, or do we have to revert back to manual null checking in Kotlin?
val meaningOfLife : String? = null
when meaningOfLife {
exists -> println(meaningOfLife)
else -> println("There's no meaning")
}
One of possible ways is to match null first so that in else branch the String? is implicitly converted to String:
val meaningOfLife: String? = null
when (meaningOfLife) {
null -> println("There's no meaning")
else -> println(meaningOfLife.toUpperCase()) //non-nullable here
}
This is a special case of a smart cast performed by the compiler.
Similar effect can be achieved with is String and else branches -- is String-check is true when the value is not null.
For more idioms regarding null-safety please see this answer.
You can accomplish that as follows:
val meaningOfLife: String? = null
when (meaningOfLife) {
is String -> println(meaningOfLife)
else -> println("There's no meaning")
}
FYI, the particular situation in the question has a way simple solution with the ?: operator of default value:
println(meaningOfLife ?: "There's no meaning")
The example in the question is probably a simplified real situation, so a null check is how I would do it. IMHO if is a better way to go when you have a binary chose of control flow:
if(meaningOfLife != null)
println(meaningOfLife)
else
println("There's no meaning")
Takes exactly the same number of lines, BTW.
Try this:
val meaningOfLife : String? = null
meaningOfLife?.let { println(it) } ?: println("There's no meaning")
let in stdlib