I know you can do a map which amounts to the same thing, but sometimes a for loop is a little bit more readable. I was surprised to see that a for is not an expression.
val fnxs = for (x in xs) { fn(x) }
I know you can do a map which amounts to the same thing, but sometimes a for loop is a little bit more readable. I was surprised to see that a for is not an expression.
val fnxs = for (x in xs) { fn(x) }
Kotlin would need a yield
expression to return a (useful) value. yield
is on the roadmap for Kotlin 1.1. I’d be interested, whether for
will become an expression then.
I wouldn’t be unhappy with the yield at all, but is it really required?
Ie, what’s the difference between
for (x in xs) {
fn(x)
}
and
val ys = for (x in xs) {
fn(x)
}
The for without yield can just throw away the value. Depends how fussy you are on if “expressions should never throw away their return value”.
xs.map { fn(y) }
val ys = xs.map { fn(y) }
Is the same kind of thing.
Maybe you could show an example where map
is less readable, because in this case I clearly favor map
over for
.
val fnxs = xs.map(fn)
I think this will introduce unnecessary ambiguity and fragmentation. That’s one of the things that bother me about Scala or Haskell. You end up with 10 different ways to do the same thing.
I agree (with fragmentation). But I don’t think for as an expression would do that, in fact I think its odd its an exception (not an expression). try, if, when are all expressions, why is for is the odd one out.
It’s not a big deal, I won’t try to convince you with toy examples as people will always have their own viewpoint on what is elegant and what is ugly.
Looping over lists, there isn’t much need for a for/yield sort of thing, since that’s what map, or flatmap, or other such things do. A yield statement would be much more useful in a recursive data structure like a tree.
Consider the humble in-order tree traversal. In principle it’s really simple:
class Tree<T> {
fun traverse(consumer: (T)->Unit) {
if(isLeaf()) {
consumer(leafVal)
} else {
left.traverse(consumer)
consumer(nodeVal)
right.traverse(consumer)
}
}
}
But what if you only really want to consume the first N elements of a potentially huge tree, but in sorted order? If you could rewrite that above code to say yield(nodeVal)
or something similar instead of just invoking the consumer, now you’ve got a lazy tree traversal without dealing with lazy lists and whatnot.
That would be seriously cool.
What would be a nice way to write this in Kotlin, given that for loops are not expressions.
for ( k <- 1 to rs.getMetaData.getColumnCount ) yield rs.getString(k)
(1..rs.getMetaData.getColumnCount).map { k -> rs.getString(k) }
Thanks
Comprehensions (yield
etc) may still be a benefit, but for now one can use coroutine-based generate()
from this library: GitHub - Kotlin/kotlinx.coroutines: Library support for Kotlin coroutines