Purpose of repeat function - kotlin

Using kotlin I can repeat an action in at least two ways:
val times = 5
// First option
for (i in 0 until times) {
print("Action $i")
}
// Second option
repeat(times) {
print("Action $it")
}
I'd like to know the purpose of repeat.
Should the traditional for loop be replaced with repeat function if possible?
Or are there special cases for this function?
Are there any advantages in repeat function?
EDIT
I've made some research about this question. As long as kotlin is open source project, I could download the sources and check git history.
I found that
1) repeat function is a replace for times function extension.
public inline fun Int.times(body : () -> Unit)
2) KT-7074. times function has become deprecated. But why?

It's just a matter of convenience (shortens the code). There are even more ways for example using an IntRange and forEach
(0..4).forEach {
println(it)
}
0 1 2 3 4
They all serve the same purpose, so the choice is yours.
You don't need to worry about performance either, since repeat and forEach are inline functions, which means the lambda code is copied over to the call site at compile time.

Next lines are all just my opinion:
there are no special cases when you should or shouldn't use repeat
function.
it has more concise syntax.
In places where you don't need to manipulate the loop counter or need to repeat only some simple action I would use that function.
It's all up to you to decide when and how to use it.

From Standard.kt:
/**
* Executes the given function [action] specified number of [times].
*
* A zero-based index of current iteration is passed as a parameter to [action].
*
* #sample samples.misc.ControlFlow.repeat
*/
#kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
contract { callsInPlace(action) }
for (index in 0 until times) {
action(index)
}
}
As you can see repeat(times) is actually for (index in 0 until times).
There is also a zero-based loop counter and it is: it.
Should the traditional for loop be replaced with repeat function if
possible?
I can't find any reason for that
Or are there special cases for this function?
None I can think of.
Are there any advantages in repeat function?
None I can think of, or maybe(?) just 1:
for educational purposes, I suppose it's easier to teach
that repeat(n) { } performs n iterations of the block of statements inside the curly brackets.

Related

How does this extension property to capitalize the first letter of every word in a string work?

I'm recently trying to get into kotlin (coming from java) and did some beginner coding challenges.
The task is to write a function that capitalizes the first letter of every word in a string
I could solve the task in my own way, but I still don't understand this sample solution:
fun capitalizeSentence(str: String) {
println(str.split(" ").joinToString(" ") { it.capitalize() })
}
Can someone explain to me, why this lambda expressions manages to capitalize the first letter of every word, even when using the joinToString method right after the split method?
joinToString() accepts an optional transform function which it applies to each item before joining. It might be confusing to you, because this code performs operations in a different order than the code flow itself. This code is effectively an equivalent of this one:
str.split(" ")
.map { it.capitalize() }
.joinToString(" ")

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.

Inverted "repeat" function in Kotlin

There is a Kotlin Standard Library repeat() function that allows for executing a given function specified number of times and retrieving the index of a current repetition. For example:
repeat(3) {
println(it)
}
Is there a function that will do the same in reverse order? In a way, the indices descend?
No, there's no version of the stdlib repeat() function that counts down.
That's probably because it's so easy to use other structures such as forEach().  (And if you care enough about the passed value to want a particular ordering, then that would probably be a good idea as it'd make it explicit.)
But if you really don't want to use that directly, it's dead easy to write your own:
inline fun repeatReverse(times: Int, action: (Int) -> Unit)
= (times downTo 1).forEach(action)

Execution order of kotlin `.also {}` function

I know .also { } is intended to be used for logging. That is exactly what I want to do.
var count = 1
count++.also { print("count is $it") }
In this example I expect the log to be
count is 2
But it actually prints:
count is 1
Is there a way different way to use also here?
Your problem is not related to also.
You are using the postfix (count++) increment operator which returns the value of a variable before it has been incremented, which is 1.
If you use the prefix increment (++count) operator it will first assign the new value and then return it, in this case 2. Note that you need paratheses in this case:
(++count).also { print("count is $it") }
You mentioned that also is intended for logging. I don't think that is true. It is merelely a scope function which offers the receiver as it (or as you name it) inside the labmda and returns the receiver.

Modifying an object during iteration [duplicate]

This question already has an answer here:
How to modify/partially remove a range from a BTreeMap?
(1 answer)
Closed 6 years ago.
I'm trying to translate some simple data structures I use in C++ over to Rust, starting with an interval tree, but I don't understand how to modify my underlying data structure (here an std::collections::BTreeSet) during iteration - essentially so I can merge overlapping entries as they appear.
If I use the standard idiom for iterating over a collection, I get the following message about it being immutable "cannot borrow self.storage as mutable because it is also borrowed as immutable", and there doesn't appear to be an option to get a mutable iterator that I can see ... what am I missing?
C++ code:
inline void Insert(const Interval& interval)
{
auto it = storage.insert(interval);
// check to see if we overlap the previous element,
// if we do, start our merge loop from there
if (it != begin()) {
const_iterator prev = std::prev(it);
if (prev->Overlaps(*it)) it = prev;
}
while (it != end()) {
const_iterator nx = std::next(it);
if (nx != end() && it->Overlaps(*nx)) {
const Interval u = it->Union(*nx);
it = storage.erase(it);
it = storage.erase(it);
it = storage.insert(it, u);
} else
break;
}
}
Rust code:
/// Add a new interval into the tree
pub fn insert(&mut self, other: Interval) -> () {
self.storage.insert(other);
for int in self.storage.iter() {
if other <= *int {
break
} else if other.overlaps(int) {
self.storage.remove(&other);
self.storage.remove(int);
self.storage.insert(other.union(int).unwrap());
}
}
}
You cannot mutate a BTreeSet while you're iterating on it – that would invalidate the iterator. Unfortunately, unlike C++, Rust doesn't have insert or remove methods that return updated iterators (and if it did, they would have to be methods on the iterator itself).
BTreeSet doesn't offer a mutable iterator, because the only additional operation you could do is obtain a mutable reference to the elements in the set. However, doing this could potentially screw up the set's ordering, so it's not available.
The most straightforward solution is to build a list of operations to perform during the iteration, then perform them once the iteration is complete. However, for this algorithm, this won't quite work, since you might need to merge an interval that is the result of a previous merge. So, once you've found a pair of intervals to merge, you need to keep track of the relevant values, break out of the iteration, perform the merge, then restart the iteration. BTreeSet provides a range method that lets you iterate over a subset of the set's values, so you might want to use that instead of iter, which always iterates over all the values. However, range is unstable as of Rust 1.8, so you'll need a nightly compiler to be able to use it.