What are the reasons to not support fori in Kotlin...
# getting-started
h
What are the reasons to not support fori in Kotlin:
for(int i = 0; check(i); i++)
but instead
var i = 0; while(check(i) { i++ }
?
j
I guess the intent is not very clear in the first
for
v
Copy code
for (i in 0..Int.MAX_VALUE) {
    if (!check(i)) break
    // ...
}
h
Sure, there are some workarounds. I am just curious why this existing Java syntax isn't supported.
k
I guess it's for clarity. Java's
for
syntax was copied from C, and C was the first language that introduced a condition in a
for
statement. That was an anomaly. Most other languages at the time of C's creation, and many other languages created since then, had/have a clear separation between iteration of a range (
for
) and iteration based on a condition (
while
). So I would think the Kotlin team didn't decide to "drop" this syntax from Java, but instead decided to do what many other languages already do, since Kotlin is not Java.
đź’Ż 2
c
Other reasons why the traditional
for
is not a good idea: • off-by-one errors: an iterator will never throw
IndexOutOfBoundsException
• off-by-one errors: it's easy to miss a
for (int i = 1; i < array.size; i++)
• off-by-one errors: it's easy to miss a
for (int i = 0; i <= array.size; i++)
• off-by-one errors when reversing: it's easy to make a mistake in
for (int i = array.size; i >= 0; i--)
(note that it's now
>=
) • performance : many structures are really bad at indexed access (
LinkedList
, trees, `Set`…), so it shouldn't be the default
k
Those 5 off-by-one errors are important, but if you really want a
for i...
type of control structure in Kotlin, think about what you actually want: it's basically a sequence, and you take it while a check returns true, so in Kotlin you can actually say it exactly like it is:
Copy code
generateSequence(0) { it + 1 }
    .takeWhile { check(it) }
    .forEach { }
v
Does that version fail on hitting
Int.MAX_VALUE
, or wrap around?
k
It wraps around, just like the OP's
for
loop.
c
A more “philosophical” reason is that the older syntax used by C and Java is a very procedural mechanism. You are directly telling the computer what to do. While this can give a lot of flexibility for low-level programming tasks, it’s often hard to understand the intent behind procedural code at a glance, and easy to make subtle errors. Off-by-one errors are one of the most common security vulnerabilities, and has led to some of the most significant flaws like Heartbleed. It can be very useful, but can also be very dangerous. Kotlin, however, is a pragmatic and declarative language. It’s not trying to match the speed and flexibility of low-level machine programming tasks, it’s more optimized for developing applications at a higher level of abstraction. As such, when one normally encounters something like a
for(int i = 0;...)
loop, most of the time you don’t actually care about the values in the parameters. You’re just trying to iterate over a data structure, or in some cases iterate over a sequence of numbers. So Kotlin optimized its
for
loop for that task, which operates directly on an
Iterator
. You are declaring that you want to iterate over the entries in a list, but you no longer need to tell the computer how to iterate. It’s much more difficult to mis-use an
Iterator
than it is to mess up the indices of a list. This move from procedural to declarative programming is a big driving force behind much of the Kotlin language and its ecosystem. It takes a slightly different way of thinking about code, but once you really get used to the declarative/functional style of programming, you’ll realize how much cleaner, more readable, and more correct your code will be.
đź’Ż 5
âž• 6
s
I'm with @Vampire here, I'm not sure if I have in all my years of Java ever seen another check function than
i<c.length/size
, and the Kotlin version for that is a for-loop iterating over a range:
for(i in 0..c.lastIndex)
If there is a more complicated check-function I'm with @Klitos Kyriacou and his generateSequence.takeWhile-construct. But most often we iterate over an Iterator (or Sequence) with no need for an index variable. and if you want to iterate over an Array or Iterable and need next to the content also the index then there's the forEachIndexed-function. So my take on why the basic version isn't supported in Kotlin is that there are better versions for each specific usecase.