rangeTo is not intuitive at all


#1

Just had a bug by trying to traverse list backwards

val list = listOf(1, 2, 3)
for (i in (list.size - 1)..0) {
        println("$i. ${list[i]}")
}

This code really looks like it should work but it does not
You have to use downTo for this case and step for any customization and it has to be positive even for counting down!

Guess I’m too used to C/Java style for loop

int[] array = {1, 2, 3};
int size = array.length;
for (int i = size - 1; i >= 0; i--) {
    System.out.println(i + ". " + array[i]);
}

It seems while loop is superior in every way compared to for loop in case you don’t want to have to deal with iterators. When iterators are ok there are plenty extension functions.
What kotlin for loop is for then?


#2

In my opinion, classic for(;;) loop is mostly obsolete in kotlin. The only exception is not yet complete API for floating point ranges. For now it is awkward to use.
Both for used for iterables and while loops could be replaced by library functions freeing up keywords, so I personally think that i some future release classic for should be completely removed.

As for range downTo, I am not sure whether it is reasonable to make automatic comparison between borders. It could easily be done, but the way it is now, it prevents some errors that is not easy to track. You can always use step -1 to count down.


#3

not with downTo. Step has to be positive


#4

Indeed it is. Sorry for misleading.


#5

So, you’re arguing that this range expression should guess its direction based on which end is greater than the other.
Let’s consider various list sizes:

  • for a list of size 2 we get 1..0 which should be equivalent (as proposed) to 1 downTo 0. Seems ok for now.
  • for an empty list we get -1..0 which will change the iterator order, so you iterate through indices -1 and 0.

Is it what you expected to get?


#6

You can use the well known “goes to” operator from C++ in Kotlin:

    var index = list.size
    while (index --> 0) {
        println(list[index])
    }

:grinning:


#7

not at all. I’m arguing that .. looks like magic but does no magic things so why have it? Specifically in for loop case.
This is about for loop not range expression.

So why have for loop in language? Only reason I can see is to prevent trolls from saying ‘$lang does not even. No for loop for you.

In C/Java for loop is specific case of while loop that encapsulates most common iteration pattern and I guess was just inherited from algol like languages.
And what is the reason for it in kotlin?


#8

Well, I suppose these things are a matter of taste but I do like Kotlin’s for statement and do find it intuitive.

When I see downTo I know straightaway that the loop’s going downwards without having to figure out whether the start-point is greater than the end-point. And, given it’s going downwards, it’s logical that any step should be positive.

Similarly, when I see until I know that the range excludes the end-point and, if it’s just .. then it includes the end-point.

Also, in the latest coding conventions, it actually recommends that you use for rather than forEach in many cases.

So, thankfully, I don’t see the humble for loop being removed from the language any time soon.


#9

Please stop saying things like this. I am asking not just you, but everybody. What makes this look magic in comparison to =, ++, or any other operator?

Different languages have different language constructs, and assign different semantics to ones they share. You simply cannot take your existing knowledge and expect the language to work like you are used to with other languages.

The documentation may not be clear (if so, say so on this forum or open an issue, so the Kotlin team can fix it), or the concept may be difficult to understand (there are plenty of concepts that I have difficulty understanding), but I am pretty sure there is no magic.


#10

It should iterate starting at the first number you give it, and ending at the last. It shouldn’t care what numbers you give it.

Now if I want to use it to, for instance, get a substring, 1..5 should be functionally equivalent to 5..1

I don’t see why this would be hard.


#11

I also think the use of library functions instead of better range syntax is just lazy. Swift has x...y for "x through y, inclusive", x..<y for " x (inclusive) to y (exclusive)", x... for “x and greater”, ...y for "less than or equal to y", and ..<y for "less than y". So much capability with a language-level operator, and Kotlin just stopped at the first meaning.

It’s… Saddening, if not annoying.


#12

It would make the iteration go up in some cases and down in other cases. Exactly as in the example for (i in (list.size - 1)..0) I had given.


#13

In that case somebody will complain about this behavior being totally non intuitive too :slight_smile:
This is not a case in C style for which is forced to be explicit.


#14

for (i in 4 downTo 1) print(i)