refactor if to takeIf and return "return" without label kotlin - kotlin

I am trying to write more idiomatic Kotlin code and I am stuck with the best way to refactor this if condition. Basically when the condition if true (fragment is GenericActionsBottomSheetDialog instance in a list of Fragments) I return the funcion itself.
Here is what I had and how I refactored it. Is there better way to achieve it? After my refactoring it get worse:
Before refactor:
supportFragmentManager.fragments.iterator().forEach {
if (it is GenericActionsBottomSheetDialog)
return
After refactor:
supportFragmentManager.fragments.iterator().forEach { it ->
it.apply {
takeIf { it is GenericActionsBottomSheetDialog }?.apply { return }}}

If this forEach is the only thing in your current function (which it should IMO), you could get rid of the non-local return by using takeWhile instead:
supportFragmentManager.fragments
.takeWhile { it !is GenericActionsBottomSheetDialog }
.forEach {
// do stuff
}
/!\ be careful that this changes semantics if there is other stuff after the forEach in the same function declared with fun.
If you expect many fragments in the list, you could also use asSequence() before takeWhile so you don't create an intermediate list.

Here's one possibility, which separates the decision from the action:
if (supportFragmentManager.fragments.any{ it is GenericActionsBottomSheetDialog })
return
I think this approach makes the intent clearest. (It's also about the most efficient.)
any() simply checks each item in turn, stopping when it finds a match (or when it reaches the end of the list). Kotlin has many functions like this (inspired by functional programming languages) that use lambdas to operate on lists and other structures. They tend to be named for what they do, rather than how they do it — which makes code using them both short and easy to read. (You should be writing code for people to read, as much as for computers to execute!)
For completeness, here's another approach, which uses filterIsInstance():
if (supportFragmentManager.fragments
.filterIsInstance<GenericActionsBottomSheetDialog>)
.isNotEmpty())
return
There are bound to be many other ways. But I agree with the commenter that your ‘refactored’ approach, while using many more Kotlin functions, has little else to recommend it!

This is an opinion based question, and answers cannot be any different.
That being said: there is nothing wrong with if clauses. From what I can see from your current question, I'd leave it with an if.
Now, if you really do not want to use it, filter elements that are not of type GenericActionsBottomSheetDialog and apply whatever function you want on them (the part that is in your else clause, which we do not see).
EDIT:
In case you only want to check if the object of the GenericActionsBottomSheetDialog exists in the collection, you can perhaps do it like this:
val dialogExists = supportFragmentManager.fragments
.firstOrNull { it is GenericActionsBottomSheetDialog} != null
if (dialogExists) {
return
}

#gidds solution is IMO the most idiomatic one:
if (supportFragmentManager.fragments
.any { it is GenericActionsBottomSheetDialog }) return
I would like to add this solution eliminating the if:
supportFragmentManager.fragments
.firstOrNull { it is GenericActionsBottomSheetDialog }
?.run { return }
It's a matter of taste which one you pick, I prefer the first one.
I was wondering why you use the iterator? You could simply do:
supportFragmentManager.fragments.forEach {

Related

How to repeat Mono while not empty

I have a method which returns like this!
Mono<Integer> getNumberFromSomewhere();
I need to keep calling this until it has no more items to emit. That is I need to make this as Flux<Integer>.
One option is to add repeat. the point is - I want to stop when the above method emits the first empty signal.
Is there any way to do this? I am looking for a clean way.
A built-in operator that does that (although it is intended for "deeper" nesting) is expand.
expand naturally stops expansion when the returned Publisher completes empty.
You could apply it to your use-case like this:
//this changes each time one subscribes to it
Mono<Integer> monoWithUnderlyingState;
Flux<Integer> repeated = monoWithUnderlyingState
.expand(i -> monoWithUnderlyingState);
I'm not aware of a built-in operator which would do the job straightaway. However, it can be done using a wrapper class and a mix of operators:
Flux<Integer> repeatUntilEmpty() {
return getNumberFromSomewhere()
.map(ResultWrapper::new)
.defaultIfEmpty(ResultWrapper.EMPTY)
.repeat()
.takeWhile(ResultWrapper::isNotEmpty)
}
// helper class, not necessarily needs to be Java record
record ResultWrapper(Integer value) {
public static final ResultWrapper EMPTY = new ResultWrapper(null);
public boolean isNotEmpty() {
return value != null;
}
}

Async Wait Efficient Execution

I need to iterate 100's of ids in parallel and collect the result in list. I am trying to do it in following way
val context = newFixedThreadPoolContext(5, "custom pool")
val list = mutableListOf<String>()
ids.map {
val result:Deferred<String> = async(context) {
getResult(it)
}
//list.add(result.await()
}.mapNotNull(result -> list.add(result.await())
I am getting error at
mapNotNull(result -> list.add(result.await())
as await method is not available. Why await is not applicable at this place? Instead commented line
//list.add(result.await()
is working fine.
What is the best way to run this block in parallel using coroutine with custom thread pool?
Generally, you go in the right direction: you need to create a list of Deferred and then await() on them.
If this is exactly the code you are using then you did not return anything from your first map { } block, so you don't get a List<Deferred> as you expect, but List<Unit> (list of nothing). Just remove val result:Deferred<String> = - this way you won't assign result to a variable, but return it from the lambda. Also, there are two syntactic errors in the last line: you used () instead of {} and there is a missing closing parenthesis.
After these changes I believe your code will work, but still, it is pretty weird. You seem to mix two distinct approaches to transform a collection into another. One is using higher-order functions like map() and another is using a loop and adding to a list. You use both of them at the same time. I think the following code should do exactly what you need (thanks #Joffrey for improving it):
val list = ids.map {
async(context) {
getResult(it)
}
}.awaitAll().filterNotNull()

Is it considered bad convention when in iterating through two maps, I don't check if key exists in one of them?

I have two maps, let's call them oneMap and twoMap.
I am iterating through all the keys in oneMap, and if the key exists in twoMap I do something
like
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
if (twoMap.containsKey(oneMapKey)) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
}
To avoid having more nested if statements, I was wondering if instead I could get rid of the
if (twoMap.containsKey(oneMapKey)) check. if twoMap doesn't contain the oneMapKey, we get a null object, and my code still works fine. I was wondering if this is considered bad convention though
fun exampleFunc(oneMap: Map<String, Any>, twoMap: Map<String, Any>) {
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal = twoMap[oneMapKey]
if (twoMapVal == oneMapVal) {
//do more stuff
}
//do more stuff, I have more if statements
}
}
It depends. Do you wanna execute the "more stuff" or not?
If you do not wanna execute it you should keep the if condition. Though, if you are concerned about indentation (and deep if hierarchies) you can consider breaking out of the loop:
for((oneMapKey, oneMapVal) in oneMap) {
if (!twoMap.contains(oneMapKey)) continue // continue with next iteration
// do more stuff
}
If your map does not contain null values you can also get the value and check if the result was null (which means the key was not present in the map):
for((oneMapKey, oneMapVal) in oneMap) {
val twoMapVal: Any = twoMap[oneMapKey] ?: continue // continue with next iteration
// do more stuff
}
So its always good practice the remove useless code and (in my opinion) to have less if-hierarchies, as you can easily loose focus when you have lots of nested conditions.
As Tenfour04 says, omitting the containsKey() check is only an option if the map values aren't nullable; if they are, then []/get() gives no way to distinguish between a missing mapping and a mapping to a null value.
But if not (or if you want to ignore null values anyway), then I'd certainly consider omitting the check; the resulting code would be slightly shorter and slightly more efficient, without losing clarity or maintainability.  It could also avoid a potential race condition.  (Though in a multi-threaded situation, I'd be considering more robust protection!)
One variation is to use let() along with the safe-call ?. operator to restrict it to non-null cases:
for ((oneMapKey, oneMapVal) in oneMap) {
twoMap[oneMapKey]?.let { twoMapVal ->
if (twoMapVal == oneMapVal) {
// Do more stuff
}
// Do more stuff
}
}
Using ?.let() this way seems to be a fairly common idiom in Kotlin, so it should be fairly transparent.

Clean code , testing and re-usability clarification

Aiming for clean code and testing . Each function / method , should do one and only one thing. this is the theory. to illustrate that i want to share with you some code and then question.
Let's say we need a method that will return a list of players if a condition is true and an empty list of the condition is false.
First approach: One method:
public List<int> ListOfPlayersIDs(int InputNumber)
{
if (Condition)
{
return new List<int>(new int[] {1, 2, 3}); // return a list with items
}
else
{
return new List<int>();//return an empty list
}
}
So here the method ListOfPlayersIDs performs two things:
returns a list of players
Verify if a condition is valid and returns an empty list if not
To divide those "functionality" we can have one method to check the condition and one to return the list of players.
Something like this:
Second approach: Two methods:
First Method
public bool ArePlayerValidForThisNumber(int InputNumber)
{
If (condition)
return true;
else return false;
//Or simply return condition;
}
Second method
public List<int> ListOfPlayersIDs(int InputNumber)
{
return new List<int>(new int[] {1, 2, 3}); // return a list with items
}
My question is :
Which approach do you follow and apply in your coding.
For me the second one is testable, reusable and each method does exactly what it suppose to do. but isn't just a theory in books? I read a lot of code and it does not respect this pattern.
What's your take on this?
It depends (tm). And it depends if you make your code cleaner and easier to understand when you break things into smaller methods.
Personally I would keep the external interface the same (the method can return a filled list or empty), as otherwise, if your client needs to do code if/else clause, you might be leaking logic. Also, I would use an approach called 'code at two levels of abstraction' or 'each method should descend one level of abstraction'. By doing this the final code might look like
public List<int> ListOfPlayersIDs(int InputNumber)
{
if (methodDescribingTheBusinessCondition()) {
return methodDescribingPositiveOutcome();
} else {
return methodNameDescribingNegativeOutcome();
}
}
The idea is that all of this should read like "normal" English, so someone reading the code will get the idea of what's going on without having to know all the nitty gritty details. Here each method is also doing just one thing and the method that orchestrates the whole thing is usually called a "policy" (as it describes your functionality).
If your method is simple, this level of abstraction might make it more difficult to understand.
Last but not least, this approach is explained in a few books (Clean Code to be very specific), and it's used as a good practice in professional development.

Optimizing a method with boolean flag

I have a method whose purpose is to retrieve collection items.
A collection can contain a mix of items, let's say: pens, pencils, and papers.
The 1st parameter allows me to tell the method to retrieve only the itemTypes I pass (e.g, just pens and pencils).
The 2nd parameter flags the function to use the collection's default item types, instead.
getCollectionItems($itemTypes,$useCollectionDefaultItemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
if($useCollectionDefaultItemTypes) {
// get collection's items using collection->itemTypes
}
else {
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
}
What feels odd is that if I set the $useCollectionDefaultItemTypes to true, there is no need for the function to use the first parameter. I was considering refactoring this method into two such as:
getCollectionItems($itemTypes); // get the items using $itemTypes
getCollectionItems(); // get the items using default settings
The problem is that the methods will have lots of duplicate code except for the if-statement area.
Is there a better way to optimize this?
Pass in $itemTypes as null when you're not using it. Have your if statement check if $itemTypes === null; if it is, use default settings.
If this is php, which I assume it is, you can make your method signature function getCollectionItems($itemTypes = null) and then you can call getCollectionItems() and it will call it as if you had typed getCollectionItems(null).
It's generally a bad idea to write methods that use flags like that. I've seen that written in several places (here at #16, Uncle Bob here and elsewhere). It makes the method hard to understand, read, and refactor.
An alternative design would be to use closures. Your code could look something like this:
$specificWayOfProcessing = function($a) {
//do something with each $a
};
getCollectionItems($processer) {
foreach() {
foreach() {
foreach() {
// lots of code...
$processor(...)
// lots of code...
}
}
}
}
getCollectionItems($specificWayOfProcessing);
This design is better because
It's more flexible. What happens when you need to decide between three different things?
You can now test the code inside the loop much easier
It is now easier to read, because the last line tells you that you are "getting collection items using a specific way of processing" - it reads like an English sentence.
Yes, there is a better way of doing this -- though this question is not an optimization question, but a style question. (Duplicated code has little effect on performance!)
The simplest way to implement this along the lines of your original idea is to make the no-argument form of getCollectionItems() define the default arguments, and then call the version of it that requires an argument:
getCollectionItems($itemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
getCollectionItems() {
getCollectionItems(collection->itemTypes)
}
Depending on what language you are using, you may even be able to collapse these into a single function definition with a default argument:
getCollectionItems($itemTypes = collection->itemTypes) {
foreach() {
foreach() {
foreach() {
// lots of code...
// get collection's items using $itemTypes
}
// lots of code...
}
}
}
That has the advantage of clearly expressing your original idea, which is that you use $itemTypes if provided, and collection->itemTypes if not.
(This does, of course, assume that you're talking about a single "collection", rather than having one of those foreach iterations be iterating over collections. If you are, the idea to use a null value is a good one.)