What is the purpose of 'let' keyword in Kotlin [duplicate] - kotlin

This question already has answers here:
Example of when should we use run, let, apply, also and with on Kotlin
(6 answers)
Closed 3 years ago.
We can write the code with or without let as follows.
var str = "Hello World"
str.let { println("$it!!") }
OR
var str = "Hello World"
println("$str!!")
What is the Actual use of let?.Is that more memory efficient or more readable?

let is one of Kotlin's Scope functions which allow you to execute a code block within the context of an object. In this case the context object is str. There are five of them: let, run, with, apply, and also. Their usages range from but are not exclusive to initialization and mapping.
They are all very similar but they differ in terms of how the context object is referenced and the value that is returned. In the case of let the context object is referenced by the it keyword as opposed to the this keyword. The return value is whatever is returned from the lambda code block. Other scope functions like apply will return the context object instead.
Because let returns whatever the lambda block evaluates to, it is most suited to performing a mapping of some kind:
var upperStr = str.let { it.toUpperCase()}
apply is a more suited function for what you are doing.
To answer your question as to which code is more preferable, it really depends on what you are using the scope function for. In the above case there is no reason to use let. If you are using IntelliJ it will give a warning saying the call to let is redundant. Readability here is a matter of preference, and may be preferred.
The let function is useful when you wish to perform a null safe operation on an Object by using the the safe call operator ?. When doing this the let code block will only be executed if the object is not null. Another reason to use let is if you need to introduce new variables for the operation but you want to confine them to the scope of the let block. This is true for all scope functions, so I reiterate that let is best used for a mapping operation.
Edit: The let function should incur no additional cost. Normally we would expect the lambda/Code-block to be compiled to a Function object but this is not the case for an inline function in Kotlin for which the compiler will emit code not dissimilar to the second code example you have given. See the documentation for more information.

One of usages you can check nullable types
var str: String? = null
str?.let { println("$it!!") }
it's equal
if (str != null) {
System.out.println(str);
}
in Java, but shorter and more useful

let takes the object it is invoked upon as the parameter and returns the result of the lambda expression.
Kotlin let is a scoping function wherein the variables declared inside the expression cannot be used outside.
One of the examples would be here :
fun main(args: Array<String>) {
var str = "Hello World"
str.let { println("$it!!") }
println(str)
}
You can find more information on Kotlin let function here

Related

Why does `EffectScope.shift` need the type parameter `B`?

The move to the new continuations API in Arrow brought with it a handy new function: shift, in theory letting me get rid of ensure(false) { NewError() } or NewError().left().bind() constructs.
But I'm not sure how to properly use it. The documentation states that it is intended to short-circuit the continuation, and there are no conditionals, so it should always take the parameter, and (in either parlance) "make it a left value", and exit the scope.
So what is the type parameter B intended to be used for? It determines the return type of shift, but shift will not return. Given no more context, B can not be inferred, leading to this kind of code:
val res = either {
val intermediate = mayReturnNull()
if (intermediate == null) {
shift<Nothing>(IntermediateWasNull())
}
process(intermediate)
}
Note the <Nothing> (and ignore the contrived example, the main point is that shifts return type can not be inferred – the actual type parameter does not even matter).
I could wrap shift like this:
suspend fun <L> EffectScope<L>.fail(left: L): Nothing = shift(left)
But I feel like that is missing the point. Any explanations/hints would be greatly appreciated.
That is a great question!
This is more a matter of style, ideally we'd have both but they conflict so we cannot have both APIs available.
So shift always returns Nothing in its implementation, and so the B parameter is completely artificial.
This is something that is true for a lot of other things in Kotlin, such as object EmptyList : List<Nothing>. The Kotlin Std however exposes it as fun <A> emptyList(): List<A> = EmptyList.
For Arrow to stay consistent with APIs found in Kotlin Std, and to remain as Kotlin idiomatic as possible we also require a type argument just like emptyList. This has been up for discussion multiple times, and the Kotlin languages authors have stated that it was decided too explicitly require A for emptyList since that results in the best and most consistent ergonomics in Kotlin.
In the example you shared I would however recommend using ensureNotNull which will also smart-cast intermediate to non-null.
Arrow attempts to build the DSL so that you don't need to rely on shift in most cases, and you should prefer ensure and ensureNotNull when possible.
val res = either {
val intermediate = mayReturnNull()
ensureNotNull(intermediate) { IntermediateWasNull() }
process(intermediate) // <-- smart casted to non-null
}

Using inline function kotlin

I know there was documented in main kotlin page, but there is no clear explanation about when to use it, why this function need a receiver as a function. What would be the correct way to create a correct definition of inline function.
This is inline function
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY, block: (date: String) -> String): String {
return try {
var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
val date = sdf.parse(this.orEmpty())
sdf = SimpleDateFormat(outputDate, Locale.US)
block(sdf.format(date ?: Date()).orEmpty())
} catch (ex: Exception) {
block("")
}
}
The same way we also can do
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY): String {
return try {
var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
val date = sdf.parse(this.orEmpty())
sdf = SimpleDateFormat(outputDate, Locale.US)
sdf.format(date ?: Date()).orEmpty()
} catch (ex: Exception) {
""
}
}
If anyone could have a detail explanation about this?
Edit:
I understand that the inline function will insert the code whenever it called by the compiler. But this come to my attention, when I want to use inline function without functional parameter receiver type the warning show as this in which should have a better explain. I also want to understand why this is such recommendation.
There are few things here.
First, you ask about using a function with a receiver.  In both cases here, the receiver is the String? part of String?.toDateString().  It means that you can call the function as if it were a method of String, e.g. "2021-01-15 12:00:00".toDateString(…).
The original String? is accessible as this within the function; you can see it in the sdf.parse(this.orEmpty()) call.  (It's not always as obvious as this; you could simply call sdf.parse(orEmpty()), where the this. is implied.)
Then you ask about inline functions.  All you have to do is to mark the function as inline, and the compiler will automatically insert its code wherever it's called, instead of defining a function in the usual way.  But you don't need to worry about how it's implemented; there are just a few visible effects in the code.  In particular, if a function is inline and accepts a function parameter, then its lambda can do a few things (such as calling return) that it couldn't otherwise do.
Which leads us to what I think is your real question: about the block function parameter.  Your first example has this parameter, with the type (date: String) -> String — i.e. a function taking a single String parameter and returning another String.  (The technical term for this is that toDateString() is a higher-order function.)
The toDateString() function calls this block function before returning, applying it to the date string it has formatted before returning it to the caller.
As to why it does this, it's hard to tell.  That's why we put documentation comments before functions: to explain anything that's not obvious from the code!  Ideally, there would be a comment explaining why you're required to supply a block lamdba (or function reference), when it's not vital to what the function does.
There are times when blocks passed this way are very useful.  For example, the joinToString() function accepts an optional transform parameter, which it applies to each item before joining it to the list.  If it didn't, the effect would be a lot more awkward to obtain.  (You'd probably have to apply a map() to the collection before calling joinToString(), which would be less efficient.)
But this isn't one of those times.  As your second example shows, toDateString() would work perfectly well without the block parameter — and then if you needed to pass the result through another function, you could just call it on toDateString()'s result.
Perhaps if you included a link to the ‘main kotlin page’ where you saw this, it might give some more context?
The edited question also asks about the IDE warning.  This is shown when it thinks inlining a function won't give a significant improvement.
When no lambdas are involved, the only potential benefit from inlining a function is performance, and that's a trade-off.  It might avoid the overhead of a function call wherever it's called — but the Java runtime will often inline small functions anyway, all on its own.  And having the compiler do the inlining comes at the cost of duplicating the function's code everywhere it's called; the increased code size is less likely to fit into memory caches, and less likely to be optimised by the Java runtime — so that can end up reducing the performance overall.  Because this isn't always obvious, the IDE gives a warning.
It's different when lambdas are involved, though.  In that case, inlining affects functionality: for example, it allows non-local returns and reified type parameters.  So in that case there are good reasons for using inline regardless of any performance implications, and the IDE doesn't give the warning.
(In fact, if a function calls a lambda it's passed, inlining can have a more significant performance benefit: not only does the function itself get inlined, but the lambda itself usually does as well, removing two levels of function call — and the lambda is often called repeatedly, so there can be a real saving.)

Kotlin expression fun vs normal fun - differences

Let's assume that I have two functions which do the same stuff.
First one:
fun doSomething() = someObject.getSomeData()
Second one:
fun doSomething(): SomeData {
return someObject.getSomeData()
}
Are there any technical differences between expression functions and standard function in Kotlin excluding the way how they look?
Is compiled output the same?
Are there any advantages using one instead another?
As #Sơn Phan says, they both compile to exactly the same bytecode.
So the differences are simply about conciseness.  The expression form omits the braces and return; it also lets you omit the return type (using type inference as needed).  As the question illustrates, the expression form can be shorter — and when all else is equal, shorter tends to be easier to read and understand.
So whether the expression form is appropriate is usually a matter of style rather than correctness.  For example, this function could be on one line:
fun String.toPositiveIntegers() = split(",").mapNotNull{ it.toIntOrNull() }.filter{ it >= 0 }
But it's a bit long, and probably better to split it.  You could keep the expression form:
fun String.toPositiveIntegers()
= split(",")
.mapNotNull{ it.toIntOrNull() }
.filter{ it >= 0 }
Or use a traditional function form:
fun String.toPositiveIntegers(): List<Int> {
return split(",")
.mapNotNull{ it.toIntOrNull() }
.filter{ it >= 0 }
}
(I tend to prefer the former, but there are arguments both ways.)
Similarly, I rather like using it when the body is a simple lambda, e.g.:
fun createMyObject() = MyObject.apply {
someConfig(someField)
someOtherConfig()
}
…but I expect some folk wouldn't.
One gotcha when using the expression form is the type inference.  Generally speaking, in Kotlin it's good to let the compiler figure out the type when it can; but for function return values, that's not always such a good idea.  For example:
fun myFun(): String = someProperty.someFunction()
will give a compilation error if the someFunction() is ever changed to return something other than a String — even a nullable String?.  However:
fun myFun() = someProperty.someFunction()
…would NOT give a compilation error; it would silently change the function's return type.  That can mask bugs, or make them harder to find.  (It's not a very common problem, but I've hit it myself.)  So you might consider specifying the return type, even though you don't need to, whenever there's a risk of it changing.
One particular case of this is when calling a Java function which doesn't have an annotation specifying its nullability.  Kotlin will treat the result as a ‘platform type’ (which means it can't tell whether it's nullable); returning such a platform type is rarely a good idea, and IntelliJ has a warning suggesting that you specify the return type explicitly.
1. Compiled output
Yes the compiled output will be completely the same
2. Advantage
You usually use expression function when the body of a function is only one line of expression to make it a oneliner function. Its advantage mainly about making the code more concise. Imagine instead of all the brackets and return, you only need a = to make things done.

LiveData map transformations in kotlin

Transformations.map in LiveData transformations take two arguments :
#NonNull LiveData source
#NonNull final Function func
I tried to make the function like this:
val localLiveData = #some live data of type LiveData<User>
Transformations.map(localLiveData, s->{return s.name = "Hi"})
but this shows error cannot unresolved "s"
finally i got it working by this :
Transformations.map(localLiveData) {
s.name = "Hi"
return#map s
}
How this thing is working map has only one argument? (noob in kotlin)
Most of the problems here are with Kotlin's lambda syntax, which is slightly different from that of some other languages.
In Kotlin, a lambda must have braces.  But the -> is optional in some cases (if the lambda takes no parameters; or if it takes one and you're referring to it with the dummy name it).
This is one reason why your first version fails; it would need the s -> moved inside the braces.  (Another is that in Kotlin, an assignment is not an expression, and doesn't return a value, so you can't use it in a return.)
Your second works because in Kotlin, if the last parameter is a lambda, it can be moved outside the parenthesis.  (This allows for higher-order functions that look like language syntax.  In fact, if the lambda is the only parameter, you can omit the parentheses entirely!)
I don't know LiveData, but I wonder if the return#map is doing the right thing: it will return not just from the lambda, but from the map() method itself.  (Such non-local returns aren't needed very often, and can be confusing.)
Also, a lambda doesn't need an explicit return; it returns the value of its last expression.
So I suspect that a more concise version would be:
Transformations.map(localLiveData) { it.name = "Hi"; it }

Migrate Java Option call to kotlin

I'm taking my first steps with kotlin.
I am migrating some my existing java code to kotlin.
I have the folllowing line:
storyDate.ifPresent(article::setPublishDate);
Where storyDate is an Optional and article has a method setPublishDate(Date) method.
How would I migrate this line to kotlin?
The auto migrator at https://try.kotlinlang.org is
storyDate.ifPresent(Consumer<Date>({ article.setPublishDate() }))
But this line doesn't compile with the kotlin compiler.
I strongly prefer using extension functions and extension fields, so I've written smth like
val <T> Optional<T>.value: T?
get() = orElse(null)
And then you can use it anywhere (after import) like
myOptional.value?.let {
// handle here
}
It’s rather uncommon to use Optional in Kotlin. If you can make storyDate work as an ordinary unwrapped type, such constructs can often be expressed with a simple let call:
storyDate?.let {
article.setPublishDate(it)
//probably property access works as well:
article.publishDate = it
}
How it works: The safe call ?. will invoke let only if storyDate is not null, otherwise the whole expression evaluates to, again, null. When the variable is not null, let is called with a simple lambda where storyDate is accessible by it (or you can rename it to whatever you like).
Side note:
If storyDate really must be Optional, you can still use the depicted construct by unwrapping it like this:
storyDate.orElse(null)?.let {}
storyDate.ifPresent { Article.setPublishDate(it) }
or
storyDate.ifPresent(Article::setPublishDate)
will work.
In the first example, it denotes the value in the optional instance, which is the Date in the optional storyDate.
I assumed that Article is a class, which has the setPublishDate(Date) static method, because class names are always capitalized.
But if article is an instance, not a class, and it has non-static method, then the following will work.
// article = Article(/* some Article-typed object */)
storyDate.ifPresent { article.setPublishDate(it) }
it has the same meaning as the above one, i.e., the actual Date value in Optional.