Using Kotlin's scope functions in not exhaustive with / when - kotlin

I'm pretty new with Kotlin and I'm trying to figure out Kotlin's scope functions.
My code looks like this:
with(something) {
when {
equals("test") -> var1 = "test123"
startsWith("test2") -> var2 = "test456"
contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
}
}
So before I entered the third check with the .let function my with function does not need to be exhaustive (I'm not returning something, I'm only doing assignments). In my third check I'm using .let as a null-check ... but only for an assignment of it.var3 (if it is not null). I don't need to return anything while I know that Kotlin's .let function returns the result of the body by standard.
Nevertheless now my with/when needs to be exhaustive otherwise it won't compile anymore.
This got me thinking and trying out different things. I found these ways to solve this issue:
I can add an else to my with/when so it becomes exhaustive but actually I don't need an else and I don't want to use it in this case.
I can add another .let, so it looks like this: myNullableVar?.let { it.var3 = "test789" }.let{} .... but this looks kinda hacky to me. Is it supposed to work like this?
Use If(xy==null){...}else{...} stuff but I thought I can solve this with Kotlin differently
Because I'm new with Kotlin I'm not really sure how to handle this case properly. I would probably just go with my second idea because "it works". Or should I don't use .let for null-checks? Add another empty .let{}? Or did I not get the null-safety concept at all? I feel a little bit lost here. Thanks for any help.

This seems to be an unfortunate combination of features…
A when can be non-exhaustive only when it doesn't return a value.  The problem is that the with() function does return a value.  And since the when is at the bottom, its value is what gets returned, so in this case it must be exhaustive.
So why doesn't it insist on an else branch even if you omit the "test3" branch?  That's because assignments don't yield a value.  (They evaluate to Unit, which is Kotlin's special type for functions that don't return a useful value.)  If every branch gives Unit, then Kotlin seems* to be happy to infer a default branch also giving Unit.
But the "test3" branch returns something else — the type of myNullableVar.  So what type does the when infer?  The nearest common supertype of that type and Unit, which is the top type Any?.  And now it needs an explicit else branch!
So what to do?
You've found a few options, none of which is ideal.  So here are a few more, ditto!
You could return an explicit Unit from that branch:
contains("test3") -> { myNullableVar?.let { it.var3 = "test789" }; Unit }
You could return an explicit Unit from the with():
contains("test3") -> myNullableVar?.let { it.var3 = "test789" }
}
Unit
}
You could give an explicit type for the with(). (It has two type parameters, so you'd need to give both, starting with the type of its parameter):
with<String, Unit>("abc") {
I haven't found a single obvious best answer, I'm afraid…
And to answer your last question: yes, ?.let{ is perfectly idiomatic and common for null checks.  In this particular case, replacing it with an if happens to solve the type problem:
contains("test3") -> { if (myNullableVar != null) myNullableVar.var3 = "test789" }
But as well as being long-winded, if myNullableVar is a property and not a local variable, then it opens up a race condition (what if another thread sets it to null in between the test and the assignment?) so the compiler would complain — which is exactly why people use let instead!
(* I can't find a reference for this behaviour.  Is there an official word on it?)

Related

How to handle a forEach loop that returns early based on an enum except for one path in Kotlin

We have an API service call that returns a bunch of validation messages. In each message there is a string that contains an error code.
Our implementation converts the validation string into an enum value and then we process the enumeration as there are some error code we just don't care about.
The question becomes, how to handle the loop of messages in a Kotlin way:
response.validationErrors?.forEach {
val mediaFailure = decodeValidationMessage(it.message)
if (mediaFailure != MediaFailure.Unknown) {
return when (mediaFailure) {
MediaFailure.Encrypted -> DomainResponse(ErrorReasonCode.ERR_DOCUMENT_ENCRYPTED)
MediaFailure.NotSupported -> Response.validationFailed()
MediaFailure.InternalError -> Response.serviceFailed()
else -> throw NotImplementedError()
}
}
}
Here we loop through all the messages, then once the message error is not "Unknown" it returns the necessary response to the caller.
However, IntelliJ wants the else path, even though the if prevents that from happening.
Is there a proper Kotlin way of implementing this kind of loop?
From what I understood, you want to return a response for the first mediaFailure which is not MediaFailure.Unknown and you don't want that throw NotImplementedError() part in your function.
One way to fix this is to remove the if condition and continue the forEach loop when MediaFailure.Unknown is found.
response.validationErrors?.forEach {
val mediaFailure = decodeValidationMessage(it.message)
return when (mediaFailure) {
MediaFailure.Encrypted -> DomainResponse(ErrorReasonCode.ERR_DOCUMENT_ENCRYPTED)
MediaFailure.NotSupported -> Response.validationFailed()
MediaFailure.InternalError -> Response.serviceFailed()
MediaFailure.Unknown -> return#forEach // continue the loop
}
}
I think this is one of the many cases when it pays to step back from the code a bit and try to look at the big picture. To ask “What's the ultimate goal here? What am I trying to achieve with this code?”
(In traditional, lower-level languages, almost anything you want to do with a list or array requires a loop, so you get into the habit of reaching for a for or while without thinking. But there are often alternative approaches in Kotlin that can be more concise, clearer, and harder to get wrong. They tend to be more about what you're trying to achieve, rather than how.)
In this case, it looks you want to find the first item which decodes to give a known type (i.e. not MediaFailure.Unknown), and return a value derived from that.
So here's an attempt to code that:
val message = response.validationErrors?.asSequence()
?.map{ decodeValidationMessage(it.message) }
?.firstOrNull{ it != MediaFailure.Unknown }
return when (message) {
MediaFailure.Encrypted -> DomainResponse(ErrorReasonCode.ERR_DOCUMENT_ENCRYPTED)
MediaFailure.NotSupported -> Response.validationFailed()
MediaFailure.InternalError, null -> Response.serviceFailed()
else -> throw NotImplementedError()
}
This is still fairly similar to your code, and it's about as efficient. (Thanks to the asSequence(), it doesn't decode any more messages than it needs to.) But the firstOrNull() makes clear what you're looking for; and it's obvious that you go on to process only that one message — a fact which is rather lost in the original version.
(If there are no valid messages, message will be null and so this will return serviceFailed(), as per comments.)
There are of course many ways to skin a cat, and I can think of several variations. (It's often a worthwhile exercise to come up with some — if nothing else, it gives you more confidence in the version you end up with!) Try to pick whichever seems clearest, simplest, and best matches the big picture of what you're doing; that tends to work out best in the long run.

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
}

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.

How can I use Mono<Boolean> as condition to call second method

I'm trying to make a call to one service after checking a condition from another service in an iterative way, like so:
if (productService.isProductNotExcluded(product)){
List<Properties> properties = propertiesService.getProductDetailProperties(product)
...
}
But since isProductExcluded is returning Mono<Boolean> I'm using this approach, which seems really odd:
Flux<Properties> properties = productService.isProductNotExcluded(productId)
.filter(notExcluded -> notExcluded)
.map(ok-> propertiesService.getProductDetailProperties(product))
...
Which is the correct way to deal with this kind of situation?
For a predicate which returns a Mono<Boolean>, you can also use filterWhen which takes a publisher as a predicate. Something like this:
Flux<Properties> properties = Mono.just(productId)
.filterWhen(prodId -> productService.isProductNotExcluded(prodId))
.map(validProductId -> propertiesService.getProductDetailProperties(validProductId));
What you are doing is not odd. I personally wouldn't return a boolean in a reactive function Mono<Boolean> if I can avoid it, but it's not wrong and sometimes you don't have a choice.
I personally would have an if/else statement in the map, for clarity. I would also change the name of the function, and rewrite the isNot part.
Flux<Properties> properties = productService.isExcluded(productId)
.flatMap(isExcluded -> {
if(!isExcluded)
return propertiesService.getProductDetailProperties(product);
else
return mono.empty();
});
This is matter of opinion and coding taste, but I find this to be a lot more readable, because you can read the code and understand it straight away. But this is a personal taste.
all() operator can be used.
According to the doc. all() Emits a single boolean true if all values of this sequence match
Mono all(Predicate<? super T> predicate) {}

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.