example:

fun main(){
    var userInput: String?
    //userInput = null
    userInput = "asbdef"
    var inputLength:Int? = userInput!!.length
    println("Length of the string is :"+inputLength)
}

Output : Length of the string is :6

fun main(){
    var userInput: String?
    userInput = null
    //userInput = "asbdef"
    var inputLength:Int? = userInput!!.length
    println("Length of the string is :"+inputLength)
}

Output : Unresolved reference: length

I want to know why it gives compile error?

If I just replace (!!) operator with (?) it compiles well but prints output as null.

PS: I'm newbie in Kotlin

1

There are 1 answers

0
Adam Millerchip On BEST ANSWER

The ?. operator short-circuits if the left side evaluates to null. So the result of nullVariable?.length is null and .length is never evaluated. Your first example is effectively doing:

println("Length of the string is :" + null)

The !! operator says "throw a NullPointerException if the left side is null. Otherwise, we know it's not null on the right side". You can see this if you change your second example a little:

val userInput: String? = null
val inputLength:Int = userInput!!.length // throws NullPointerException

However, I'm not sure why are you are getting Unresolved reference: length. It looks like that the compiler is doing some optimization when you assign null directly to userInput, so rather than compiling it to a String? which throws an NPE at runtime, it knows the value is only null (not String?) at compile time, and therefore can't have the length property because null is not a reference.

You can force it to give you to NullPointerException by adding a layer of abstraction via a function call:

fun main(){
    var userInput: String? = "foo"
    userInput = alwaysNull()
    val inputLength:Int = userInput!!.length // NullPointerException
}

fun alwaysNull(): String? = null

I don't see anything n the Null Safety documentation about the difference in behaviour between initializing in one line / via a function call vs. assigning null directly to a var though, so what's happening under the hood to get Unresolved reference is just a guess.