Kotlin "let{}" Doesn't Provide Smart Cast - kotlin

Just learned Kotlin Nullable type and let{} function which replaces the if (xx != null) {} operation.
But one thing I am confused is that, we all know and I Think the Complier Should Know that when we use let{}, the variable/object who is calling this function is possiblly null, however the complier still requires me to add the safe call operator "?" after the variable name instead of providing Smart Cast like it does in if (xx != null) {}. Why?
My piece of code:
fun main() {
var number1: Int? = null
//val number2 = number1.let { it + 1 } ?: 10 //doesn't work, not quite "smart"
val number2 = number1?.let { it + 1 } ?: 10 //works, must have "?"
println(number1)
println(number2)
}

You've already got answers in the comments, but just to explain the ? thing...
Kotlin lets you make null-safe calls on nullable variables and properties, by adding ? before the call. You can chain this too, by doing
nullableObject?.someProperty?.someFunction()
which evaluates nullableObject, and if it's non-null it evaluates the next bit, otherwise the whole expression evaluates to null. If any part of the chain evaluates as null, the whole expression returns null.
So it has this short-circuiting effect, and you can use the elvis "if null" operator to create a default value if you can't evaluate the whole chain to a non-null result:
nullableObject?.nullableProperty?.someFunction() ?: defaultAction()
and once you introduce the null check in the chain, you have to add it for every call after that - it's basically propagating either the result of the previous bit, or the null it resolved to, so there's a null check at each step
The let block is just a scope function - you use it on a value, so you can run some code either using that value as a parameter or a receiver (a variable or this basically). It also has the side effect of creating a new temporary local variable holding that value, so if the original is a var it doesn't matter if that value changes, because your let code isn't referring to that variable anymore.
So it's useful for doing null checks one time, without worrying the underlying value could become null while you're doing stuff with it:
nullableVar?.let { it.definitelyIsNotNull() }
and the compiler will recognise that and smart cast it to a non-null type. An if (nullableVar != null) check can't guarantee that nullableVar won't be null by the time the next line is executed.

Related

Null check before using variable in function

I am wondering if there is a better way of null checking and assigning value like in this example
val result: Clazz? = if (variable == null) null else someFun(variable)
variable?.let(::someFun)
You can use the Kotlin scope function let .
let is often used for executing a code block only with non-null values. To perform actions on a non-null object, use the safe call operator ?. on it and call let with the actions in its lambda.
So in this case someFun is only called if variable is not null. Otherwise null is returned.
The longer form of this would be:
variable?.let { someFun(it) }
where it is the non-null value of variable. However:
If the code block contains a single function with it as an argument, you can use the method reference (::) instead of the lambda:
So we can shorten it to the
variable?.let(::someFun)
form

Cannot Understand the Tail-end Insertion of Linked List in Kotlin [duplicate]

According to the Kotlin docs, the ?. operator represents a 'safe call', meaning that if it's used in a chain of method calls, the entire chain will return null if the value of whatever it's used on is null.
But what about if it's used on the left side of an assignment? Since the left side isn't the side that's 'returning' anything it seems like it probably has a different effect. Here's an example of what I'm talking about:
val myObj = SomeObj()
myObj?.property = SomeClass.someFunc() // What does ?. do in this context?
It means that if one of the safe calls on the left-hand side fails (i.e. its receiver is null), then the whole assignment is skipped, and the expression on the right-hand side is not evaluated at all.
val nullable: Container? = null
nullable?.x = f() // f is not called
(runnable demo)
I'm seeing a fun question & answer in Kotlin just now. Even if the answer is very nice, but I want to clarify it in more detailed.
The assignment expression below:
myObj?.property = SomeClass.someFunc()
is transformed to Java bytecode by Kolin as below:
val it = myObj;
if(it != null){
it.property = SomeClass.someFunc();
}
so there is no problem in multiple threads. It still works fine and I have tested it on github. But it will result in the Thread Interference problem, which means it will modify the property on different references when myObj is changed.
Except the assignment expression can be short-circuited, others also can be short-circuited. For example:
val array:Array<Any>? = null;
// v--- short-circuited
array?.set(0,SomeClass.someFunc());
// ^--- never be called

Instantiated class in Kotlin still possibly null. Why?

Question is simple:
In Kotlin, when I instantiate a fragments arguments with a Bundle(), the system still needs the arguments object to be reassured with !!. The arguments should be definitely not null by now, right? So why is that needed?
Here is the code:
private fun openPinCodeFragment(mode: PinView.Mode) {
currentFragment = PinCodeFragment()
currentFragment?.run {
arguments = Bundle()
arguments!!.putSerializable(MODE, mode)
}
openFragment(currentFragment)
}
If I remove the !! then:
You're setting the value of a variable which was defined outside of this scope (the declaration of arguments is not visible in your code).
No matter what you assign, it could have been changed by the time code execution reaches the next line to a null value by another Thread, that's why you have to use the !! here. I'd suggest defining arguments either in local scope with val or making it non-nullable in its definition.
This happens because arguments is of Bundle? type, this means that it can be either Bundle or null.
Instead of using an if to check whether it is null, like you would to in Java, the operators !! and ? were introduced.
For example if you want your code to be correct without using !! you could add:
if (arguments != null) {
arguments.putSerializable(MODE, mode)
}
Using these operators you have the following flexibility:
!! - you tell the compiler that the value cannot be null, it will throw error otherwise;
? - you don't care that much, if it is not null then it will access method and might return result, otherwise the result of such call is null and no action is made.

What is the difference between not-null checks in Kotlin?

There are some ways to fulfill a null-checking in Kotlin:
1.
if(myVar != null) {
foo(myVar)
}
2.
myVar?.let {
foo(it)
}
3.
myVar?.run {
foo(this)
}
What are the difference between these ways?
Are there any reasons (performance, best practice, code style etc.) why I should prefer on way over the other?
!! is to tell the compiler that I am sure the value of the variable is not null, and if it is null throw a null pointer exception (NPE) where as ?. is to tell the compiler that I am not sure if the value of the variable is null or not, if it is null do not throw any null pointer.
Another way of using a nullable property is safe call operator ?.
This calls the method if the property is not null or returns null if that property is null without throwing an NPE (null pointer exception).
nullableVariable?.someMethodCall()
All three code are behave same null check in operation-wise.
?. is used for chain operations.
bob?.department?.head?.name // if any of the properties in it is null it returns null
To perform a chain operation only for non-null values, you can use the safe call operator together with let
myVar?.let {
foo(it)
}
the above code is good for code style and performance
more details refer Null Safety
The ways 2 and 3 are more idiomatic for Kotlin. Both functions are quite similar. There is little difference with argument passing.
For example, we have a nullable variable:
var canBeNull: String? = null
When you working with T.run you work with extension function calling and you pass this in the closure.
canBeNull?.run {
println(length) // `this` could be omitted
}
When you call T.let you can use it like lambda argument it.
canBeNull?.let {
myString -> println(myString.length) // You could convert `it` to some other name
}
A good article about Kotlin standard functions.
All three are roughly equivalent.
The if case is more like most other languages, and so many developers may find it easier to read.
However, one difference is that the if case will read the value of myVar twice: once for the check, and again when passing it to foo(). That makes a difference, because if myVar is a property (i.e. something that could potentially be changed by another thread), then the compiler will warn that it could have been set to null after the check. If that's a problem (e.g. because foo() expects a non-null parameter), then you'll need to use one of the other cases.
For that reason, the let case has become fairly common practice in Kotlin. (The run case does just about the same thing, but for some reason isn't as popular for this sort of thing. I don't know why.)
Another way around it is to assign myVar to a temporary value, test that, and then use that. That's also more like other languages, but it's more verbose; many people prefer the conciseness of the let case — especially when myVar is actually a complicated expression.
The examples in your question don't show the true reason to decide.
First of all, since you're not using the return value of foo, you should use neither let nor run. Your choice is between also and apply.
Second, since you already have the result you want to null-check in a variable, the difference fades. This is a better motivating example:
complexCall(calculateArg1(), calculateArg2())?.also {
results.add(it)
}
as opposed to
val result = complexCall(calculateArg1(), calculateArg2())
if (result != null) {
results.add(result)
}
The second example declares an identifier, result, which is now available to the rest of the lexical scope, even though you're done with it in just one line.
The first example, on the other hand, keeps everything self-contained and when you go on reading the rest of the code, you are 100% confident that you don't have to keep in mind the meaning of result.
Kotlin have new features with NullPoint-Exception as Compare to Java.
Basically When we do Coding in Java , then we have to Check with !! in every Flied.
But in Kotlin, it is Easy way to Implement First
as Like,
Suppose, in Kotlin
var response:Json?=Null
response:Json?.let {
this part will handle automatic if response is Not Null....then this Block start Executing }?.run {
This is Nullable But, where we Can put Warring } So, I am Suggest you Guys to Start Work in Kotlin with this Features Provided by Kotlin.
(Flied)?.let { Not Null Value Comes Under }?.run{ Null Value Code }
This will Handle to NullPoint Exception or Protect You App for Crash
What you want to achieve
What you want to achieve is that the Kotlin compiler does a smart cast on the variable you are working with.
In all of your three examples, the compiler can do that.
Example:
if(myVar != null) {
foo(myVar) // smart cast: the compiler knows, that myVar can never be null here
}
The choice
Which one of the options to use, is really a matter of style. What you should not do is mix it up to often. Use one and stick to it.
You don't need to worry about performance since let and run are inlined (see inline function). This means that their code (body) is copied to the call site at compile time so there is no runtime overhead.

What's use of nullable in Kotlin [duplicate]

This question already has answers here:
In Kotlin, what is the idiomatic way to deal with nullable values, referencing or converting them
(4 answers)
Closed 4 years ago.
I do not know what's use of nullable in some case in Kotlin. Let me hold an example.
There is a method.
fun hello(name: String)
As you see, the param name is non null. Then I will use it.
hello(bob!!) // bob is a nullable string
If bob is null, above code will throw KotlinNullPointerException. So I have to wrap check.
if(bob != null) {
hello(bob!!)
}
So in this situation, what's the best practice? And what's use of nullable?
It is a matter of you code business logic to decide.
Usually you will want to use the '!!' operator in case you are 100% sure that bob is not null. In that case '!!' is a clean non-verbose way to ignore the option that 'bob' is null.
If there is a chance that bob is null, use if/else or in case that it is a business error it is advisable to throw an appropriate business exception or handle it in the usual way you are handling errors in your project.
This is how you would use such a function:
fun hello(bob: String) {
println(bob);
}
hello("Bob!!");
What this means is that the function hello has a parameter named bob, with a datatype of String.
In your example, you are giving the hello function a variable that has not been declared (bob), and as such the JVM cannot pass along anything but null. If you want to pass in a variable named bobby, the code would look like this:
fun hello(bob: String) {
println(bob);
}
val bobby = "Hello!!!";
hello(bobby);
Hope this helps in your endeavors :)
What's use of nullable?
Take for example a boolean variable which can only hold 2 types of values, true of false. There is no way to signify "undefined". Sometimes we need a way to tell that variable is in an undefined state. For eg, in database or network interaction, you may not receive any value so then variable has to exist in some undefined state and that's what null value signifies.
This not just applies to Kotlin, it applies to any language.
what's the best practice?
With nullable types, there is always a risk of null pointer exception, so better check for null before accessing it, and in here
if(bob != null) {
hello(bob!!)
}
no need to do bob!!, just bob will do, since you have done a null check, Compiler keeps track of the null check and will let you use that variable.
Use non-null assertion (!!) when you are absolutely sure the variable is not null and in that case, no need to surround with null check as well.