XTend For-Loop Support and Adding Range Support
Asked Answered
P

6

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
}
}
Posse answered 26/8, 2012 at 1:28 Comment(0)
S
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: ..<

Stanfordstang answered 16/5, 2013 at 7:13 Comment(0)
R
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.

Raquel answered 2/2, 2013 at 5:45 Comment(2)
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.Willwilla
see my answer below if you also need the iteration index within the functionRetired
C
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()
}
Corkhill answered 5/8, 2013 at 18:45 Comment(1)
This has been suggested to be added to the core Xtend library in bugs.eclipse.org/bugs/show_bug.cgi?id=489944Clea
P
4

Heh, I found the answer a little while later:

for(i: 1..3) {
    println("row ")
}
Posse answered 26/8, 2012 at 2:13 Comment(1)
You can even avoid writing Integer because it is automagically inferred by Xtend.Retired
G
3

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

Genesia answered 16/6, 2014 at 6:44 Comment(0)
R
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
Retired answered 6/11, 2014 at 18:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.