for loops for non-iterables?

1,141 views
Skip to first unread message

Mickey Killianey

unread,
Apr 9, 2012, 12:01:36 PM4/9/12
to gosu...@googlegroups.com
What's the canonical way to translate the canonical for loop in C/Java/etc. to Gosu?

for (initialization; condition; increment) {
   statement(s)
}

Note:  I'm specifically *not* talking about the Java enhanced for-loop on iterables...I'm specifically asking about the normal for-loop, for when you *don't* have a reasonable way to construct an iterable and/or want to be able to alter the iteration mid-loop.


For example:
for (double x = 0.0; x < r; x += step) {
  for (double y = 0.0; x*x + y*y < r*r; y += step) {
    // do something inside circle, including (possibly) modifying step.
  }
}

Or this:
for (int i = 0; i < args.length; i++) {
  if (arg[i].equals("-h") {
    printHelp()
    break;
  }
  if (arg[i].equals("-f") {
    i++; // grab next arg after "-f" as filename
    filename = arg[i]
  }
}


Carson Gross

unread,
Apr 9, 2012, 12:11:59 PM4/9/12
to gosu...@googlegroups.com
For better or for worse, no, not really.

I'd use a while loop for the first example.

For the second example, i'd convert the array to an iterable and use the iterator keyword:

for( arg in args.toList() iterator it ) {

  if(arg == "-h") {
    printHelp()
    break
  }

  if( arg == "-f" ) {
    if( it.hasNext() ) {
      fileName = it.next()
    } else {
      // report an error?
    }
  }
}

(Typed into email directly, apologies for compilation or api errors.)

Cheers,
Carson

--
You received this message because you are subscribed to the Google Groups "gosu-lang" group.
To post to this group, send email to gosu...@googlegroups.com.
To unsubscribe from this group, send email to gosu-lang+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/gosu-lang?hl=en.

Carson Gross

unread,
Apr 9, 2012, 12:24:31 PM4/9/12
to gosu...@googlegroups.com
Also, I should mention, if you need access to the current index in a loop, you can use the index keyword, although that doesn't help if you are trying for random access or skip ahead:

for (arg in args index i) {
  if (arg == "-h") {
    printHelp()
    break
  }
  if (arg == "-f") {
    filename = args[i + 1] //er, well, it doesn't skip ahead, but at 
                           //least it demos the 'index' keyword... 
  }
}

Hope that helps.

Cheers,
Carson

Mickey Killianey

unread,
Apr 9, 2012, 9:43:18 PM4/9/12
to gosu...@googlegroups.com
Ah...that explains why "index" is keyword highlighted in the editor.

Looking at the for loop documentation on gosu-lang (http://gosu-lang.org/docs.html#basics), I see that it also has the "iterator" keyword:


 var list = { "one", "two", "three" }
 for ( num in list iterator iter ) {
   iter.remove()
 }
I'm guessing that I can also iter.next() within the iteration to advance to the next item?

I wonder if there's an elegant way to wrap the three fields of a "for(init; condition; increment)" loop in an object that can be used in an enhanced for loop?  If you had a ForLoop object that took three blocks, for example?  Sadly, I can't see how to do it and preserve the *exact* semantics of the standard for loop...any solution I've tried has some drawbacks.  (Some implementations don't handle exceptions quite right, others don't scope neatly so you can modify the loop variable, others don't handle break and continue correctly.)

FWIW, I was surprised to discover that this kind of loop wasn't supported.   Is this in the TODO pile or the never-do pile?  Is there some compelling reason *not* to support this loop?

mk

Scott McKinney

unread,
Apr 10, 2012, 4:00:42 AM4/10/12
to gosu-lang
We added the index and iterator clauses as a means to *not* fall back
on the conventional C-style for loop. I don't know how many times in
Java I've written an iterator-style for loop only to back out and type
a conventional loop because I either needed the iterator (e.g. to call
remove()) or I needed the index of the current element. Ugh! That
just makes me mad. So in Gosu we added index and iterator clauses to
make the iterator-style loop more accommodating. It's the little
things.

More recently we added support for interval iteration. This style of
looping hammers another nail in the C-style looping coffin:

for( i in 0..9 ) {
// iterates 0 - 9 inclusively
}

You can modify an interval's endpoints to make them open like so:

0..|9 // exclusive of 9
0|..9 // exclusive of 0

You can also set a step on the interval

(0..9).step( 2 )

Or go backwards:

9..0

and intervals support more than just numbers e.g., Dates:

for( d in (start..end).step( 1 ).unit( DAYS ) ) {
print( d )
}

And, lastly, intervals are pluggable -- you can implement Gosu APIs to
make your stuff sequenceable.


But, as you've discovered there are some edge cases where the
conventional for loop has no matching for loop in Gosu. And good!
Because if we had it all matched up, we'd have what would amount to a
conventional for loop, which we want to avoid having.

In my view the conventional for loop serves a purpose, but is so
heavily overloaded that it has worn out its welcome in terms of
improving readability; actually I don't think it ever was very
readable in any form. Our brains are awesome pattern recognition
machines, so over time as Java/C programmers we've been conditioned to
quickly recognize the dozen or so mainstream overloads of the for
loop; a seasoned for-looper will grok the gunk inside the parenthesis
in nearly the same time he can read it. It's amazing, and wrong. A
bright-eyed CS 101 student will stare and wonder for what seems like
eons before anything registers. Instructor: "Well, you see all that
syntax there in the parenthesis? There's an initialization statement
in there followed by a boolean conditional expression and then
followed by another statement that may or may not increment anything.
The initializer is declared first and is executed just the one time,
following that the condition expression there is evaluated each time
the for loop cycles, it controls the lifetime of the loop... unless..
nevermind, then the last statement there (is there one there?), well
that isn't executed until after the first time the loop cycles...
makes perfect sense, right?" Student: "Er... ssuuuurre." I don't
want those. Maybe we can do better, and I'm open to that (ideas?),
but for now the while loop will suffice for the edge cases. The CS
student will struggle less with it too, IMO.

Scott

Mickey Killianey

unread,
Apr 10, 2012, 2:25:56 PM4/10/12
to gosu...@googlegroups.com
Ugh.  I spent a few hours last night using the latest Gosu plugin for IntelliJ and had an awful, terrible time, so pardon me if I'm really down on Gosu today.  (As a warmup, I was trying to solve the Google codejam problems, and the plugin kept crashing every few minutes.  I tried to use the built-in graphic editor and it, too, crashed often.

More recently we added support for interval iteration.  This style of
looping hammers another nail in the C-style looping coffin:

At this point, that seems like a dramatic overreach.  The C-style looping syntax isn't dead...it's simple, useful, and easy to understand.

I experimented with the Gosu interval last night, and my experience with it was the opposite of simple, useful, and easy to understand.  The syntax introduces weird edge cases that are unpredictable, inconsistent, and error-prone.

As an example of how unpredictable Gosu is, here's a puzzler...I challenge readers to identify the result *before* running this code snippet:

Problem:
function countUpTo(n : int) {
  var interval = 1..n
  print(interval)
  for (i in interval) {
    print(i)
       }
}
countUpTo(0)

Possible solutions:
(1)  The interval of 1 to 0 is an empty iterable, so it just prints out the interval:
1..0 step 1
(2)  The interval of 1 to 0 includes the startpoint (1), but not the endpoint (0) since 1 > 0. 
1..0 step 1
1
(3)  The code counts from 1 to 0, but identifies at runtime that 0 is less than 1 and decides to count backwards with step -1:
1..0 step -1
1
0
(4)  The code cannot create an interval because the start (1) is greater than the end (0), so it throws a runtime exception.
(5)  None of the above

(I'll put the answer at the end)

And an example of inconsistencies in the design of the index and iterator clauses, this example loops four times:
for (var word in {"foo", "bar", "baz", "qux"} index i) {
  print(word)
  i = i+1 // skip next word
}
While this example loops only twice:
for (var word in {"foo", "bar", "baz", "qux"} iterator i) {
  print(word)
  i.next() // skip next word
}

Finally, the language support is woefully incomplete, since this simple example is a compile error in the latest Gosu:
for (r in 0.0 .. Math.PI step 0.01) {
  print(r)
}

If Gosu is serious about moving forward as a community-based language, we should have a community-based discussion about language features to see what the community needs.  After playing around with this last night, I found the interval syntax to be incredibly error-prone and really, really wanted the simplicity and predictability of C-style loops.  Perhaps that would be a good first topic to kickstart the "community" part of "community Gosu"?

And lest we forget...Spoiler alert:  Puzzle answer below...



















The answer for the puzzler is "E:  None of the Above."  The interval is constructed from 1..0 with step 1, but when you actually iterate over the interval, in *spite* of the step being positive (1), it counts in the opposite direction, from 1 to 0, printing out:
1..0 step 1
1
0
What makes this even more unexpected is that you can ask the interval for its step, and it'll *still* tell you that it's going in the positive direction.  For example:
print((1..0).Step)
prints "1" instead of "-1".



Alan Keefer

unread,
Apr 10, 2012, 2:45:13 PM4/10/12
to gosu...@googlegroups.com
I have to agree that I find the interval syntax horrendously
confusing; for anyone coming from C/Java, who's used to:

for (int i = 0; i < 10; i++) { // do stuff }

Doing:

for (i in 0..|10) { // do stuff }

is not at all intuitive or easy to read, and it's easy to forget if
you should do 0..10 or 0..|10 and to do the wrong one.

I don't find myself doing that all that often, since usually I just
want to iterate over the elements in some array/collection/whatever,
but when I do really just want to loop a fixed number of times for
some reason, I find the Gosu syntax harder to get right than the Java
syntax. Perhaps if Gosu was the only language I knew, that would be
one thing, but for anyone coming from a Java background (which is
pretty much everyone that we'd want to have use Gosu), using intervals
in the for loops is pretty confusing, and I'd much rather just have a
Java/C-style for loop available.

-Alan

Scott McKinney

unread,
Apr 10, 2012, 3:33:08 PM4/10/12
to gosu-lang
Sorry to hear that.

First, I think you'd write it this way:

for( i in 0..9 ) { ... }

Which seems intuitive regardless of your background. And really, if
you're honest with yourself, I think you'll admit that's more
intuitive from first principles than the C-style way. Which is the
whole point. If Gosu provides the C-style way, Java programmers will
use it like a crutch. Fwiw, I am still a little torn on providing
it. On the one hand, absolutely, a lot of potential Gosu users are
current Java programmers and they will feel more at home as Gosu feels
more like Java. But the point of any new language is to make marked
improvements over the status quo and it's kind of difficult to claim
an improvement when you're carrying the luggage of your forebearer.
Maybe you don't like the concept of intervals, but that's Gosu's way.
I think if you give them a chance, you may change your position, or
maybe not.

Again, I still there's room for improvement, perhaps building on the
interval/iterator-style looping. Given you can extend the set of
iterables and sequenceables programmatically, there's probably
something that can be done to support a broader set of use-cases.
Your ideas are welcome.

Scott

Chris Gow

unread,
Apr 10, 2012, 3:33:36 PM4/10/12
to gosu...@googlegroups.com
I haven't used the interval style of for loops (didn't know it was
there), but I've been quite happy with:

(0..10) and using one of the collection looping methods (each,
eachWithIndex, filter,etc..)

But I like blocks and chaining. At least with the block there's less
things I need to think about - What happens if I increment the index
in my block - nothing it doesn't affect the looping at all. Granted I
can't break out of the loop, but if I need to do things like that, a
for loop is the wrong construct anyways and a while() loop would be
better (IMO in most cases).

In the few cases working with Gosu where I wasn't looping over an
iterator and I wanted a for loop, I got frustrated for 10 seconds and
figured out a more 'Gosu' way of writing it, either by converting the
'thing' into some sort of iterator or using a while loop.

My opinion is that instead of trying to write Gosu the Java or C way,
we should write Gosu the Gosu way. I guess its up to us (or the
language designers) to really figure out what that way is.

So, that's a long winded response to "I don't miss for loops in Gosu
and would rather leave them on the never-do pile."

Chris

Scott McKinney

unread,
Apr 10, 2012, 3:42:09 PM4/10/12
to gosu-lang
Mick, I think maybe, just maybe, if you type in the right syntax the
languge may not be woefully incomplete:

for (r in (0.0 .. Math.PI).step(0.01) ) {
print(r)
}

:)

Mickey Killianey

unread,
Apr 10, 2012, 5:22:13 PM4/10/12
to gosu...@googlegroups.com
Ah, I see...the syntax is:
    for (item in list index i)
but not:
    for (item in 0..9 step 2)

Perhaps you can accept it as constructive criticism, either for the documentation or the language, that this was not obvious to me.

And the rest of my comment still stands.

Q:  How many people got the puzzler right or wrong?


Mickey Killianey

unread,
Apr 10, 2012, 5:47:04 PM4/10/12
to gosu...@googlegroups.com
That's a thoughtful response.  I don't agree that a while loop is an adequate replacement for C-style for loops for my needs, but I do respect that you find it adequate for your needs.  Thanks for setting a great tone with your response!

Q1:  Do you only use Gosu at Guidewire, or have you done anything outside of Guidewire with it?
Q2:  Are you going to use Gosu to participate in the upcoming Google codejam at http://code.google.com/codejam ?

mk

Carson Gross

unread,
Apr 10, 2012, 6:21:56 PM4/10/12
to gosu...@googlegroups.com
That's a pretty good summary of my take: blocks and the high-level for() loop give you an awful lot of power, and the while() loop is always there if you need to get down into the weeds.  In Gosu you can, to a first approximation, look at a for() loop and have a pretty good sense that the loop will terminate and won't have any boundary errors in it, without delving in too deeply, and that's even more true when you use the (presumably reasonably well tested) block based methods that abstract even the for() loop away. 

I'm a high-level kinda guy, so I like that.

JMO,
Carson

On Tue, Apr 10, 2012 at 12:33 PM, Chris Gow <chri...@gmail.com> wrote:

Scott McKinney

unread,
Apr 10, 2012, 6:25:59 PM4/10/12
to gosu-lang
Mick, please let us know how the while loop is deficient as a for-loop
alternative for the cases where Gosu's iterator/interval-style looping
construct and/or use of closures doesn't fit. Maybe show some
examples where you feel the conventional for-loop adds significant
value and, most importantly, state why you feel it's significant.
Constructive feedback always helps us determine where to focus.
Thanks.

Scott

Mickey Killianey

unread,
Apr 10, 2012, 6:38:29 PM4/10/12
to gosu...@googlegroups.com
Sure...I already did, so feel free to re-read this thread and respond to the issues I raised.  (For example, the command-line arg-parser and the countUpTo() method.)

mk

Mickey Killianey

unread,
Apr 10, 2012, 6:50:04 PM4/10/12
to gosu...@googlegroups.com
It sounds like this conversation has reached a branching point, where there are three topics:
  1. Discussion of for-loops (specifically, a request for adding the C-style syntax).
  2. Discussion of the design of intervals (specifically, a request to remove them as error-prone).
  3. Discussion of the "community" aspect of a "community-released" language.  Specifically, what's the process for auditing Gosu language features?  How is community feedback gathered and reviewed?  What's the process for deciding upon the addition or removal of a language feature?  And where are conversations like this archived, so that when someone pipes up to say "Hey, why is this feature X done this way?" we can point to a coherent, discussion thread where we weigh pros and cons?
Should we start new threads for these?  I'm interested in all three.

mk

Scott McKinney

unread,
Apr 10, 2012, 7:54:08 PM4/10/12
to gosu-lang
1. Well, I haven't seen enough of a case establishing the few
instances where while loops are used as significant enough to justify
bringing back a C-style loop statement; it doesn't really provide much
of an edge, if one at all. And while loops aren't that bad
(preferable IMO) esp. considering the very few cases that you'll need
to fall back on one in Gosu. Moreover, Gosu just isn't Java; it has
it's own way of doing things and we tend to lean toward improving on
those things.

2. I'm sorry you don't like Gosu's intervals. They were vetted
internally and reviewed by anyone in our dev org who cared to
contribute and so far most people seem to like them.

3. While Gosu has a "community" release, there are no plans for a Java-
like "community process" aka JCP. If anything the JCP has proven to
be a detriment to the advancement of Java, so we're kind of CP-averse
over here. This is not to say we don't listen to sincere feedback on
the language and tools, we absolutely do, we need it, we count on it,
and it's already helped us advance the language.. But like a lot of
other programming languages (C# and Python come to mind), there are a
few guys who write and maintain its core and one guy who tries to keep
it consistent. In the near future we'll be releasing the rest of
Gosu's internals as well in hopes that we'll receive more feedback.
At some point we'll be in shape so that the whole thing will be OS and
forkable. We're just not there yet.

On Apr 10, 3:50 pm, Mickey Killianey <mic...@killianey.com> wrote:
> It sounds like this conversation has reached a branching point, where there
> are three topics:
>
>    1. Discussion of for-loops (specifically, a request for adding the
>    C-style syntax).
>    2. Discussion of the design of intervals (specifically, a request to
>    remove them as error-prone).
>    3. Discussion of the "community" aspect of a "community-released"
>    language.  Specifically, what's the process for auditing Gosu language
>    features?  How is community feedback gathered and reviewed?  What's the
>    process for deciding upon the addition or removal of a language feature?
>     And where are conversations like this archived, so that when someone pipes
>    up to say "Hey, why is this feature X done this way?" we can point to a
>    coherent, discussion thread where we weigh pros and cons?
>
> Should we start new threads for these?  I'm interested in all three.
>
> mk
>

Brian Chang

unread,
Apr 10, 2012, 11:40:55 PM4/10/12
to gosu...@googlegroups.com
A thoughtful design decision such as this belongs on some FAQ we can put on the website.

It would be nice to be able to tag (or even sticky-ify) messages on a Google group.  I don't see a way, but I probably don't have admin rights.

Scott McKinney

unread,
Apr 11, 2012, 2:22:30 AM4/11/12
to gosu-lang
Yep. Hmm... I thought either you or Carson or Cory had already
started a FAQ for the webite? Or maybe I'm thinking of Carson's Lazy
Gosu site? In any case, yeah, I can help piece one together. In
addition to tagging google messages, it might be useful to post some
of our early design topics such as intervals along with the FAQ.
Speaking of FAQs I was reading Kotlin's the other day; I like the
level of information they provide, wouldn't mind modeling after that
one.

Scott

On Apr 10, 8:40 pm, Brian Chang <bchan...@gmail.com> wrote:
> A thoughtful design decision such as this belongs on some FAQ we can put on
> the website.
>
> It would be nice to be able to tag (or even sticky-ify) messages on a
> Google group.  I don't see a way, but I probably don't have admin rights.
>
> bchan...@gmail.com

Chris Gow

unread,
Apr 11, 2012, 10:28:54 AM4/11/12
to gosu...@googlegroups.com
I primarily use Gosu for my Guidewire work, but have used it outside
of Guidewire. To be honest until the IJ plugin became available I
didn't use Gosu much outside of my GW work, that's now changed but I
have these two other projects that suck up a lot of my time - kids.

I wasn't considering participating in the Google Code Jam. See projects above :)

Chris

Chris Gow

unread,
Apr 11, 2012, 10:30:53 AM4/11/12
to gosu...@googlegroups.com
I for one am *really* looking forward to the day that the rest of Gosu
is open sourced.

Peter Rexer

unread,
Apr 11, 2012, 12:25:26 PM4/11/12
to gosu...@googlegroups.com
Let me throw on the former Product-Manager for Gosu hat and weigh in with my admittedly "I wasn't a CS major" opinion.

I applaud your puzzle.   Great puzzler.   
Your example stumped me.  Just reading it, I was expecting option 3... but I was immediately suspicious of you defining a variable called 'interval' and of the non-compact syntax.  I've grown used to much more compact syntax like:

for (i in 1..n){
  //something about i and n
}

IMHO, ideally, if the tooling was able to read your mind, you'd have been warned that 'interval' wasn't a proper interval to use in the for loop.   Not sure if the parser could easily detect that, as it looks a lot like quasi functional programming to me, and that stuff confuses my old brain.

Regarding whether you should split this into 3 threads.... please.  

-Peter

Mick Killianey

unread,
Apr 11, 2012, 5:59:38 PM4/11/12
to gosu-lang
Peter

Glad to hear that you enjoyed that puzzler. Now that readers of this
thread are experts on intervals, hopefully everyone will get this
follow-on puzzler correct:

Q: What does the following code print?

var interval = (2..0).step(-1)
print(interval)
for (i in interval) {
print(i)
}

Does it...

(1) ...iterate over the interval in steps of -1, containing three
items:
2..0 step -1
2
1
0

(2) ...iterate over three items (as in answer 1), *but* printing the
step in the first line (the toString() representation) as a *positive*
value:
2..0 step 1
2
1
0

(3) ...invert the step, looping in the positive direction.
2..0 step -1
2
3
4
...etc...

(4) ...abort after the first element.
2..0 step -1
2

(5) ...throw an exception in construction at runtime, since you can't
create an interval with a negative step?

As before, answer at the very end of this message.




On Apr 11, 9:25 am, Peter Rexer <pre...@alum.mit.edu> wrote:
> Let me throw on the former Product-Manager for Gosu hat and weigh in with
> my admittedly "I wasn't a CS major" opinion.
>
> I applaud your puzzle.   Great puzzler.
> Your example stumped me.  Just reading it, I was expecting option 3... but
> I was immediately suspicious of you defining a variable called 'interval'
> and of the non-compact syntax.  I've grown used to much more compact syntax
> like:
>
> for (i in 1..n){
>   //something about i and n
>
> }
>
> IMHO, ideally, if the tooling was able to read your mind, you'd have been
> warned that 'interval' wasn't a proper interval to use in the for loop.
> Not sure if the parser could easily detect that, as it looks a lot like
> quasi functional programming to me, and that stuff confuses my old brain.
>
> Regarding whether you should split this into 3 threads.... please.
>
> -Peter
>
> ...
>

SPOILER ALERT!

The answer is (3): Despite calling step(-1), this interval loops in
the *positive* direction, so it loops through values 2, 3, 4, ...

Followup puzzler: How long does it continue to loop? Does it loop
until...

(1) ...it hits Integer.MIN_VALUE.
(2) ...it hits Integer.MAX_VALUE.
(3) ...it overflows the int and wraps around, eventually hitting
zero.
(4) ...you kill the process. The loop index is a Number, which is
represented by a BigDecimal and grows as large as necessary.
(5) ...it runs out of memory. Intervals cache the values they
returns, so running this loop actually runs your JVM out of memory.

(The answer to this puzzler is left as an exercise for the reader.)

Peter Rexer

unread,
Apr 11, 2012, 6:05:10 PM4/11/12
to gosu...@googlegroups.com
Seems like the lesson is to not try to create a variable called an interval, and to create your interval as you initiate your for loop. 

But, that's probably just me being practical.   I tend to be like that.
I am a Product Manager, after all.    

-Peter

Alan Keefer

unread,
Apr 11, 2012, 6:22:21 PM4/11/12
to gosu...@googlegroups.com
For what it's worth, the step() method is intended to take an absolute
value, and the javadocs on the getStep() method in IIterableInterval
include the following

here are the docs on the getStep() method on IIterableInterval, where
step() and getStep() (i.e. the Step property in Gosu) are defined:

/**
* . . .
* Note if non-null, the step is a <i>positive</i> (or absolute)
increment. To iterate the interval
* in reverse order use iterateFromRight().
*/

Since intervals can be reversed and iterated in either direction, it
makes sense for step to be an absolute value so that the interval can
function properly when going either direction.

However, there's an implementation bug, such that step(-1) neither
converts the int to an absolute value nor throws an exception; as a
result, the runtime behavior is incorrect: the implementation assumes
the step is an absolute value, and since 2..0 is a reversed interval,
it subtracts the step every time. 2..0.step(1) should work as you
expect, and count down 2 1 0. step(-1) should either throw or behave
the same as step(1), and we just need to fix the implementation there.

So chalk this particular puzzle up as a bug (and please go ahead and
file it as such)

-Alan

On Wed, Apr 11, 2012 at 2:59 PM, Mick Killianey
<mickey.k...@gmail.com> wrote:

Mickey Killianey

unread,
Apr 12, 2012, 3:14:23 AM4/12/12
to gosu...@googlegroups.com
If you're serious about that being the lesson...back up!

The problem has nothing to do with whether or the variable is named "interval."  You would have exactly the same problem if you named it fred.

And instantiating the interval inside or outside the parentheses of the for() loop makes no difference, either.  The only reason why I created it outside the for loop was to make the output more instructive.

On the other hand, if you're just pulling my leg...you got me!

Mick
Reply all
Reply to author
Forward
0 new messages