10

I can't seem to find a great way to express the following in Xtend without resorting to a while loop:

for(int i = 0; i < 3; i++){
    println("row ");
}
println("your boat");

So, I guess my question has two parts:

  • Is there a better way to do the above? I didn't see anything promising in their documenation
  • A large portion of the features the language has are just Xtend library extensions (and they're great!). Is there range() functionality à la Python that I don't know about?

I ended up rolling my own and got something like the following:

class LanguageUtil {

def static Iterable<Integer> range(int stop) {
    range(0, stop)
}

def static Iterable<Integer> range(int start, int stop) {
    new RangeIterable(start, stop, 1)
}

def static Iterable<Integer> range(int start, int stop, int step) {
    new RangeIterable(start, stop, step)
}
}

// implements Iterator and Iterable which is bad form.
class RangeIterable implements Iterator<Integer>, Iterable<Integer> {
val int start
val int stop
val int step
var int current

new(int start, int stop, int step) {
    this.start = start;
    this.stop = stop;
    this.step = step
    this.current = start
}

override hasNext() {
    current < stop
}

override next() {
    val ret = current
    current = current + step
    ret
}

override remove() {
    throw new UnsupportedOperationException("Auto-generated function stub")
}

/**
 * This is bad form. We could return a 
 * new RangeIterable here, but that seems worse.
 */
override iterator() {
    this
}
}
Viliam Simko
  • 1,711
  • 17
  • 31
Bface
  • 307
  • 1
  • 2
  • 12

6 Answers6

18

The exact replacement for

for(int i = 0; i < 3; i++){
    println("row ");
}

is

for (i : 0 ..< 3) {
    println("row ")
}

Notice the exclusive range operator: ..<

rzymek
  • 9,064
  • 2
  • 45
  • 59
14

Also you can doing it more idiomatically with

(1..3).forEach[println("row")]

Very new to Xtend but man it makes programming on the jvm awesome.

Viliam Simko
  • 1,711
  • 17
  • 31
Delaney
  • 1,039
  • 1
  • 9
  • 15
  • Note that you have some restriction inside the lambda expression [], For example if you want to access a local variable localVar inside that expression, then you would receive "Cannot refer to the non-final variable localVar inside a lambda expression". I find the answer by rzymek more complete to the question of the original poster. – CuongHuyTo Aug 07 '13 at 13:53
  • see my answer below if you also need the iteration index within the function – Viliam Simko Apr 05 '16 at 23:06
5

To me a range-based forEach implies the range is somehow meaningful. For looping a specific number of times with no iteration variable, I find Ruby's times loop expresses the intent more clearly:

3.times [|println("row")]

Sadly it's not a part of IntegerExtensions, but the implementation is trivial:

def static times(int iterations, Runnable runnable) {
    if (iterations < 0) throw new IllegalArgumentException(
            '''Can't iterate negative («iterations») times.''')
    for (i: 0 ..< iterations) runnable.run()
}
Viliam Simko
  • 1,711
  • 17
  • 31
Doval
  • 2,516
  • 1
  • 22
  • 22
  • This has been suggested to be added to the core Xtend library in https://bugs.eclipse.org/bugs/show_bug.cgi?id=489944 – vorburger Mar 18 '16 at 14:27
4

Heh, I found the answer a little while later:

for(i: 1..3) {
    println("row ")
}
Andrew Regan
  • 5,087
  • 6
  • 37
  • 73
Bface
  • 307
  • 1
  • 2
  • 12
3

Since Xtend 2.6, we also support the "traditional" for-loop, just like in Java.

Stefan Oehme
  • 449
  • 2
  • 7
3

There is actually a version of forEach() that accepts a lambda with two parameters. It is useful if you need to access the iteration index within the loop.

(10..12).forEach[ x, i | println('''element=«x» index=«i»''')]

prints:

element=10 index=0
element=11 index=1
element=12 index=2
Viliam Simko
  • 1,711
  • 17
  • 31