How to handle a forEach loop that returns early based on an enum except for one path in Kotlin - 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.

Related

Doing this on kotlin is a bad practice?

The second way is a little smaller but i dont know if this is okay, can i use also just for be able to use expression body and put the first line of the cod on the side of method name?
override fun findOrdensColeta() {
view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
override fun findOrdensColeta() = view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
Yes, I think the second version is bad style. I see no good reasons to use also() like that, and several reasons not to:
also() is intended for use within expressions, where you don't have the option of adding a separate statement. (The classic case is logging a value before doing something with it.) That doesn't apply here, where two simple statements work just as well. So there's no benefit other than conciseness; using also() here is unnecessary complexity.
The second version has an expression body, which looks like it returns a useful value — but it actually returns the result of calling setProgressBarVisibility(), which is presumably Unit just like the first version. So the expression body is highly misleading.
Also, the only reason that the second version is shorter is that the first statement has been squeezed onto the same line. I don't think that's justified here* — it joins two things (the function signature and the call to setProgressBarVisibility()) that aren't directly related, and it makes the line too long for most people to read easily. (I'm surprised you find the second version easier to read. I tend to prefer conciseness, but even I find the first version a good deal easier to read — probably because it falls into a very familiar pattern that doesn't need any extra thought.)
If you cared only about reducing the number of lines, then the first version could be written like this (not recommended!):
override fun findOrdensColeta() { view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
(You could join even more lines, perhaps squeezing it all onto a single line if you wanted to make it completely unreadable!)
Conversely, if there were other good reasons for using the second version, it would be better if wrapped like this:
override fun findOrdensColeta()
= view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
So as you can see, the difference in length is mainly due to the (unjustified and confusing) line-joining, not the use of also().
So using also() here has no real benefit, as well as some significant drawbacks.
* I'm not saying you should never put the function body on the same line as its signature. That can work well if the body is an expression that's short enough to fit neatly all one line. For example:
override fun toString() = "MyClass(val1 = $val1)"
However, if that makes the line very long, or wraps onto further lines, or is a function body, then it's almost always more readable to start the body on the next line in the traditional fashion.
I believe the second one is a bad approach.
also is designed to provide the ability to modify or use the receiver and return it afterwards.
In your case, also is not containing any usages of its receiver (which is the result of view.setProgressBarVisibility(View.VISIBLE) ). Therefore it is not needed here
The second version is a bit confused to me - if you take the first one as the standard way to do things, a simple code block with two statements in it, what benefit does the second one really give you? You're basically using expression syntax to make it a one-liner - but it's not a one-liner, so you have to add a scope function just to give yourself back the curly braces so you can add another line of code!
So this:
override fun findOrdensColeta() {
view.setProgressBarVisibility(View.VISIBLE)
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
Does exactly the same thing as this:
override fun findOrdensColeta() = view.setProgressBarVisibility(View.VISIBLE).also {
model.findOrdensColeta {
handleFindOrdensColeta()
}
}
But with the latter
it appears to return a result from setProgressBarInvisibility because it's a single-expression function (the original clearly returns nothing)
the use of also which passes that result value through reinforces the idea that you're trying to return that result
the also block implies you're using that value for something (otherwise why's it there?) and it takes a moment to see that you're not
when you realise none of the above are true, now you might be wondering if you're missing something, or if the original coder intended something specific but made a mistake
Because the basic function block is so simple and readable and a natural fit for what you're doing, doing something else can throw up some questions, or be confusing to read. Sure the way it's formatted you've saved a single line, but now it's harder to understand, y'know?
This is something to watch out for in Kotlin I think (and I'm guilty of this myself) - being able to chain stuff together sometimes encourages people to go for "one-liners" that are hard to follow, but hey at least you didn't (explicitly) create a variable! That's not what you're doing here (you're creating an unnecessary variable actually!) but it feels like a similar thing - trying to make a single expression instead of doing things the old-school way.
Coding is about trying to strike that balance between simplicity and readability, and elegant efficiency, and a lot of it's about learning what tools and tricks are available, and knowing when to use them (and how best to do it) and when to avoid them. At the end of the day it's a style choice and this is just my opinion (although all the other commenters so far are saying similar things) but hopefully it's given you something to think about! I've been there too - including using expressions for functions that don't return a value at all - but I think that's all part of learning a language and the things it offers you

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

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?)

populate object from command line and check object state

I populate an object based on the users input from the commandline.
The object needs to have a certain amount of data to proceed. My solution so far is nested if-statements to check if the object is ready. Like below example.
Maybe 3 if-statements aren't so bad(?) but what if that number of if-statements starts to increase? What are my alternatives here? Let's say that X, Y and Z are three completely different things. For example let's say that object.X is a list of integers and object.Y is a string and maybe Z is some sort of boolean to return true only if object.Y has a certain amount of values?
I'm not sure polymorhism will work in this case?
do
{
if (object.HasX)
{
if (object.HasY)
{
if (object.HasZ)
{
//Object is ready to proceed.
}
else
{
//Object is missing Z. Handle it...
}
}
else
{
//Object is missing Y. Handle it...
}
}
else
{
//Object is missing X. Handle it...
}
} while (!String.IsNullOrEmpty(line));
For complex logic workflow, I have found, it's important for maintainability to decide which level of abstraction the logic should live in.
Will new logic/parsing rules have to be added regularly?
Unfortunately, there isn't a way to avoid having to do explicit conditionals, they have to live somewhere.
Some things that can help keep it clean could be:
Main function is only responsible for converting command line arguments to native datatypes, then it pushes the logic down to an object builder class, This will keep main function stable and unchanged, except for adding flag descriptions, THis should keep the logic out of the domain, and centralized to the builder abstraction
Main function is responsible for parsing and configuring the domain, this isolates all the messy conditionals in the main/parsing function and keeps the logic outside of the domain models
Flatten the logic, if not object.hasX; return, next step you know has.X, this will still have a list of conditionals but will be flatter
Create a DSL declarative rule language (more apparent when flattening). This could be a rule processor, where the logic lives, then the outer main function could define that states that are necessary to proceed

Alternative to the try (?) operator suited to iterator mapping

In the process of learning Rust, I am getting acquainted with error propagation and the choice between unwrap and the ? operator. After writing some prototype code that only uses unwrap(), I would like to remove unwrap from reusable parts, where panicking on every error is inappropriate.
How would one avoid the use of unwrap in a closure, like in this example?
// todo is VecDeque<PathBuf>
let dir = fs::read_dir(&filename).unwrap();
todo.extend(dir.map(|dirent| dirent.unwrap().path()));
The first unwrap can be easily changed to ?, as long as the containing function returns Result<(), io::Error> or similar. However, the second unwrap, the one in dirent.unwrap().path(), cannot be changed to dirent?.path() because the closure must return a PathBuf, not a Result<PathBuf, io::Error>.
One option is to change extend to an explicit loop:
let dir = fs::read_dir(&filename)?;
for dirent in dir {
todo.push_back(dirent?.path());
}
But that feels wrong - the original extend was elegant and clearly reflected the intention of the code. (It might also have been more efficient than a sequence of push_backs.) How would an experienced Rust developer express error checking in such code?
How would one avoid the use of unwrap in a closure, like in this example?
Well, it really depends on what you wish to do upon failure.
should failure be reported to the user or be silent
if reported, should one failure be reported or all?
if a failure occur, should it interrupt processing?
For example, you could perfectly decide to silently ignore all failures and just skip the entries that fail. In this case, the Iterator::filter_map combined with Result::ok is exactly what you are asking for.
let dir = fs::read_dir(&filename)?;
let todos.extend(dir.filter_map(Result::ok));
The Iterator interface is full of goodies, it's definitely worth perusing when looking for tidier code.
Here is a solution based on filter_map suggested by Matthieu. It calls Result::map_err to ensure the error is "caught" and logged, sending it further to Result::ok and filter_map to remove it from iteration:
fn log_error(e: io::Error) {
eprintln!("{}", e);
}
(|| {
let dir = fs::read_dir(&filename)?;
todo.extend(dir
.filter_map(|res| res.map_err(log_error).ok()))
.map(|dirent| dirent.path()));
})().unwrap_or_else(log_error)

Call method/function twice Vs. Saving into a variable and call once

I often come to this question when coding.
Which of the following examples is a better practice? I am aware that other factors will influence whether one or the other one is better. But in general, what are the advantages of one over the other.
if(object.getA().Value != null) {
return object.getA().Value;
}
return null;
Vs.
string x = string.null;
x = object.getA().Value;
return (x != null) ? x : null;
Here is another similar example:
var a = object.method(x).Value;
var b = object.method(x).Key;
Vs.
var y = object,method(x);
var a = y.Value;
var b = y.Key;
In other words my question is:
Is it better to call a method twice and have one less variable?
or
Is it better to save it into a variable and call the method twice?
Of course if the method results in a lot of processing it might be smart to call it once, but for general cases where the method is not too demanding and the space of the variable is not too big, which one is better and why? or which are the advantages of one or the other?
The difference between them might not make a big difference but I am trying to find better practices and will like to hear the input of some experienced programmers.
Many thanks
Caching the value in a variable is a basic optimization (related to memoizing).
When it becomes truly necessary is if the second call to the function is on the stack a significant percent of the time.
For example, if that second call is on the stack 10% or 20% of the time, then that's how much overall time you can save by caching the first result.
You can keep doing things like that, until the code is as fast as possible.
If I can give an example, ages ago I worked on an app that had code like this:
if (!Done()){
do some stuff
}
....
if (!Done()){
do some other stuff
}
Since Done() was such a short, clean, and simple function to call, it got called a lot.
Never mind that it did a lot including querying a ton of stuff from a DB and throwing most of it away.
Stackshots found the problem instantly.
It depends if you want to be thread safe and if the function could change between calls.
e.g. with
if(object.getA().Value != null) {
return object.getA().Value;
}
return null;
if the implementation of the property getter Value returned a null on the second call you would have a different answer. It could return null on the second call either by implementation of the method or if another thread casused an update between the if and the return statement that made the result of the property null.
This test is actually redundant because you are returning null if it is null. I'm guessing that you meant if (object.getA() != null). Then the previous paragraph still applies but to getA() instead of Value but the if body would throw an null reference exception if getA() returned null on the second call.
So its all down to whether you are worried about the values changing between calls.
General rule: Avoid extra variables (needlessly introduces states).
(Break the rule if calling the function twice adds too much overhead)