Discussion:
An alternative to the "continue" statement
Fabien
2008-02-26 14:00:18 UTC
Permalink
Since the regular rant about the missing "continue" statement resurfaced
again, I thought I might point to an experiment I did, which covers most of
the cases where I'd otherwise miss "continue":

http://metalua.blogspot.com/2008/02/syntax-experiments.html

Basically, it lets qualify a loop header with additional properties like
"if", "while", "until", "for". Many "break"s in for loops can be replaced
with:

* for *k, v *in *pairs(some_table) *until *leaving_condition *do*
...
* end*

* for *i=1, 10 *while *not_leaving *do*
...
* end*

and most "continue" statements can be replaced with:

* for *k, v *in *pairs(some_table) *if *not some_reason_to_skip *do*
...
* end*

I like this (still quite experimental) syntax because it integrates the
skipping/breaking condition in the loop header, and this is where it
belongs: the purpose of the "for loops" syntax, in most languages, is that
it describes how the control flow will unfold in a single, well-identified
line. When one simulates such loops with a "while...do", the condition,
stopping and iteration bits are dispatched in various places, thus making
code reading significantly more tedious.

"break" and "continue" statements deeply alter this control flow, possibly
from deep within the loop body; this ought to be stated in the loop header
line whenever possible.

NB: I'm fully aware that there are use cases for "continue" which aren't
addressed by this extension, but:
- that wasn't the subject of the experiment,
- adding a "continue" statement is pretty trivial, and already done by some
tiny sample, somewhere in the distro
- until now, this extension happened to cover all the real-life cases where
I'd use continue.
Javier Guerra
2008-02-26 14:12:28 UTC
Permalink
Post by Fabien
Basically, it lets qualify a loop header with additional properties like
"if", "while", "until", "for". Many "break"s in for loops can be replaced
i like this. of course, 'deep' breaks are usually convenient. 'deep'
continues not so much, IMO.

taking it to an extreme, i think 'if', 'while', 'until' and 'for'
(both variants) could be chainable blocks, terminated by a 'do' or
'then' ('else' too?), so you could write:

for k,v in pairs(t) while itsok(k) do
...
end

if whatever(x) until finish(y) then
...
end

while going(a) if keeps(b) for c=ever(d) until tired(e) do
...
end

does that make any sense??

i kind of like it... but not sure... it's weird
--
Javier
Fabien
2008-02-26 15:08:32 UTC
Permalink
All your examples are accepted by xloop, except "if whatever(x) until
finish(y)" (I wonder what meaning it could have actually). You can write "while
not finish(y) if whatever(x)", though, and it would be possible to add "
until...do...end" and "repeat...while..." loops; arguably, it would even
make the extension more homogeneous.

Another thing you can do is collapsing for loops together. You save an
indentation level, and more importantly, breaks escape both loops:

* for *i=1,10 *for *j=1,10 *if *i~=j *do*
...
* end*

I plan to try a couple more stuff on this base, many of them loosely
inspired by Common Lisp's loop macro.

-- Fabien.
Fabien
2008-02-26 16:02:52 UTC
Permalink
it would be possible to add "until...do...end" and "repeat...while..."
loops
Actually it wouldn't, it would introduce ambiguities: "until" and "while"
could both close a "repeat" statement, and introduce a new "until...do" /
"while...do".
Ben Sunshine-Hill
2008-02-26 19:48:57 UTC
Permalink
Post by Fabien
Since the regular rant about the missing "continue" statement resurfaced
again, I thought I might point to an experiment I did, which covers most of
http://metalua.blogspot.com/2008/02/syntax-experiments.html
Basically, it lets qualify a loop header with additional properties like
"if", "while", "until", "for". Many "break"s in for loops can be replaced
for k, v in pairs(some_table) until leaving_condition do
...
end
for i=1, 10 while not_leaving do
...
end
for k, v in pairs(some_table) if not some_reason_to_skip do
...
end
Why syntaxize it? Just have a function which wraps an iterator and a
(probably anonymous) function and produces a filtered iterator.

Ben
Fabien
2008-02-26 20:45:11 UTC
Permalink
Post by Ben Sunshine-Hill
Why syntaxize it? Just have a function which wraps an iterator and a
(probably anonymous) function and produces a filtered iterator.
The question behind syntax extensions is always: does it improve code
readability?

Generally, a syntax might improve readability if it captures a recurring
pattern, that is especially important to identify to understand a piece of
code. For instance, numerical for loops are a nice syntax, because they
capture a very common pattern, and "for i=x,y do ... end" is easier to
identify than "local i=x; while i<=y do ...; i=i+1 end". But strictly
speaking, there's no technical need to "syntaxize" it either.

There is a trade-off to find, between the cost of learning a new idiom, and
the payback of reading it more easily. xloop is an experiment to see whether
there are more idioms worth supporting with dedicated syntax in loops. I
suspect there is, because many languages offer similar features:

- Common Lisp has the arguably over-the-top loop macro
- Haskell and Python have lists by comprehension, which are quite
related to this cartesian product / filtering / iterating business
- in Perl, it's quite idiomatic to have a "continue unless foobar"
statement at the beginning of a loop

Moreover, it seems to me that most of the time, when there are non-trivial
control flow operations in a loop which make it harder to grok, it's about
nesting loops, filtering, or escaping the loop early; so a more synthetic
presentation of these might prove useful. Finally, the proposed extensions
blend quite nicely with Lua's syntax; syntaxes that respect the language's
regularity are faster learned, and therefore are more easily "worth it".

Again, this must be put back in metalua's context, where macros are
considered more expensive than in Lisp, but where there it remains much more
acceptable to extend the language than in Lua.

As you noticed, it would be possible to offer semantically equivalent
iterators in plain Lua, but how readable would it be to write the equivalent
of, say:

* for* i=1,n *for* j=1,i *until* tab[i][j]==0 *do*
...
* end*
?

-- Fabien.
Eric Tetz
2008-02-26 21:40:58 UTC
Permalink
Post by Fabien
The question behind syntax extensions is always: does it improve code
readability?
When considering that question, you should probably add ", and for
whom?" More readable to the average Foo programmer, or the Foo guru?
There's great value in economy of concepts. It's one reason many
people prefer C over it's superset, C++. Minimizing the number of
concepts one needs to know to read/write a language is particularly
valuable in a language used for end-user configuration and scripting.

I occasionally write WoW addons for my girlfriend, and I find
interacting with that community very eye opening. You'd be surprised
at how many people don't know that {x=10,y=20} and {["x"]=10,["y"]=20}
mean the same thing. Sometimes giving people too many ways to skin a
cat is not a good thing.

BTW (OT): I don't know if you guys have ever looked into the whole WoW
thing, but it wouldn't surprise me if the amount of Lua code written
for WoW addons outnumbered every other Lua application combined. It's
huge! *lol*

Cheers,
Eric
Evan DeMond
2008-02-26 21:53:47 UTC
Permalink
Post by Eric Tetz
Post by Fabien
The question behind syntax extensions is always: does it improve code
readability?
When considering that question, you should probably add ", and for
whom?" More readable to the average Foo programmer, or the Foo guru?
There's great value in economy of concepts.
I think readability's always going to be a subjective thing - as evidenced
by the multitude of individual coding styles. So given that, I'd say it's
best then to strive to keep the language's design coherent with its
philosophy.

As I understand it, Lua wants to provide "meta-mechanisms" for people to do
what they want - so I'd say we don't have "continue" for about the same
reason we have tables as the only native data structure. We can do it with
what's there already, and do it in our own way, and good taste is up to the
individual.

Personally, I wouldn't mind either way if continue were in the language, but
this is how I see it when I try to detach my perspective =)
Roberto Ierusalimschy
2008-02-27 14:34:15 UTC
Permalink
Post by Eric Tetz
BTW (OT): I don't know if you guys have ever looked into the whole WoW
thing, but it wouldn't surprise me if the amount of Lua code written
for WoW addons outnumbered every other Lua application combined. It's
huge! *lol*
For sure there are much more books about WoW addons than about Lua.

-- Roberto
Jim Whitehead II
2008-02-27 16:02:28 UTC
Permalink
On Wed, Feb 27, 2008 at 2:34 PM, Roberto Ierusalimschy
Post by Roberto Ierusalimschy
Post by Eric Tetz
BTW (OT): I don't know if you guys have ever looked into the whole WoW
thing, but it wouldn't surprise me if the amount of Lua code written
for WoW addons outnumbered every other Lua application combined. It's
huge! *lol*
For sure there are much more books about WoW addons than about Lua.
Actually there are only the two books, both of which I've been happy
to be a part of:

http://www.amazon.com/Hacking-Warcraft-ExtremeTech-Daniel-Gilbert/dp/0470110023/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1204128077&sr=8-1
http://www.amazon.com/World-Warcraft-Programming-Reference-Creating/dp/0470229810/ref=pd_bbs_2?ie=UTF8&s=books&qid=1204128077&sr=8-2

The second will be coming out in April/May and is a huge 1100 page
monster covering the entire World of Warcraft API. Hopefully it'll
encourage more sales of PiL and the Reference Manual, which we link to
quite heavily in the chapters on Lua.

- Jim
Roberto Ierusalimschy
2008-02-27 16:35:15 UTC
Permalink
Post by Jim Whitehead II
Post by Roberto Ierusalimschy
For sure there are much more books about WoW addons than about Lua.
Actually there are only the two books, both of which I've been happy
[...]
Yes, sorry. (There are other books about WoW, but not about addons.)
Post by Jim Whitehead II
Hopefully it'll encourage more sales of PiL and the Reference Manual,
which we link to quite heavily in the chapters on Lua.
Many thanks!

-- Roberto
David Manura
2008-02-28 02:47:56 UTC
Permalink
[an experiment I did lets you] qualify a loop header with
additional properties like "if", "while", "until", "for".
That seems closely related to list comprehensions:

-- List comprehension (proposed syntax
-- from http://lua-users.org/wiki/PythonLists )
t = {x*y for x=1,10 for y=1,10 if x+y >= 10}

-- For loop iterating over that list comprehension
for _,v in ipairs(t) do u[#u+1] = v end

-- Fabien's control structure (proposed syntax)
for x=1,10 for y=1,10 if x+y >= 10 do
u[#u+1] = x*y
end

The text "for x=1,10 for y=1,10 if x+y >= 10" is identical. The main difference
is that you are not building an actual list but rather invoking the code-block
for each element that would exist in such a list.

Another difference is that you add these "while" and "until" clauses for the
purpose of short-circuiting. I'm not fond of that since that makes these two
seemingly similar constructs behave differently:

-- Proposed syntax
for x=1,10 while f() do
g()
end

-- Similar standard syntax (result is quite different!)
for x=1,10 do while f() do
g()
end end

Maybe replace "while/until" with "break if":

-- Proposed syntax
for x=1,10 break if not f() do
g()
end

-- Corresponding standard syntax
for x=1,10 do if not f() then break end
g()
end

Now, if we also allow "if not f() then break end" to be re-expressed as "break
if not f()" (as in Perl), then the similarity is even more apparent:

-- Corresponding standard syntax rewritten with proposed syntax.
for x=1,10 do break if not f()
g()
end

I would recommend list comprehensions support the same syntax:

t = {x for x=1,10 break if not f()}

The "break if" has the advantage that the break is not nested (more obvious):

for x=1,10 do
local y = f()
break if not y
g(y)
end
Fabien
2008-02-28 13:09:10 UTC
Permalink
Indeed there's a lot in common between lists by comprehension and xloops,
and if both where to remain in metalua, their code would be factorized. The
former is mostly the functional equivalent of the latter, which is more
imperative.

(the clist extension can be found at:
http://repo.or.cz/w/metalua.git?a=blob;f=src/lib/extension/clist.mlua,
with a usage sample at:
http://repo.or.cz/w/metalua.git?a=blob;f=src/samples/clist_test.mlua).

It often appears that imperative traits blend better than functional ones in
Lua, for reasons I couldn't explain. Adapting ideas from CL's 'loop' macro,
I'd like to try this:

squares_to_100 = *for *i=1,100 *collect *i
sum_to_100 = *for *i=1,100 *accumulate *i, |x,y|x+y
biggest = *for *_,v *in *pairs(t) *accumulate *v, max

(The general principle is that the "do...end" would only be one of the
possible bodies of a loop, and that with some bodies, which produce values,
loops must be accepted in an expression's context, not only as statements.
Syntactical details yet to be decided).

This would supersede the comprehension part of clist. Improved
indexes/slices (such as "list[3 ... 5]") would remain relevant.

About your concern with "while/until" semantics: first, they're inspired by
the CL macro (not that it guarantees tastefulness, though). Moreover, their
sense seems consistent to me: they introduce a condition that's sufficient
to leave a loop.

If I understand correctly, your concern is that by adding "do" / "end"
keywords at various places, you change the program's meaning; I don't think
it would shock any developer: if you add some "{" / "}" randomly in
C/Java/C#/C++ code, you'll also change the program's meaning, and nobody
would consider that a problem; that's actually their whole purpose :)

Besides, a correct editor will make the problem obvious in your double-do
example, by indenting the body twice. This is actually a fairly good test
for an extension: if it's lua-ish, there are good chances that emacs'
lua-mode already knows how to indent it.

-- Fabien.
Miles Bader
2008-02-28 13:37:30 UTC
Permalink
they're inspired by the CL macro (not that it guarantees tastefulness,
though)
The usual tone when talking about the CL loop macro seems to be
derision, in my experience...

-Miles
--
Optimist, n. A proponent of the doctrine that black is white.
Fabien
2008-02-28 14:20:02 UTC
Permalink
The usual tone when talking about the CL loop macro seems to be derision
Indeed :) Actually, my reference tried to be derisive as well. Loop is a
caricature of what's IMO Lisp's original sin: the design principle that
everyone should hack the syntax in every directions for every purposes.
Granted, official coding policies state that macros shouldn't be created
gratuitously, but lispers tend to have a pretty restrictive understanding of
"gratuitousness"...

What makes loop suck are:

- its unlispy syntax: keyword-based with very little structuring
parentheses. You're welcome to dislike heavily parenthesized code, but then,
don't use CL: keep Lisp lispy!
- the incredible number of plug-ins that go in it. It's too easy, or
at least too acceptable, to add yet another loop extension for very specific
use cases.

As restated every time a syntax extension discussion occurs, syntax
plasticity comes at a price in terms of modularity and reusability. Lisp
chooses to bet everything on plasticity, whereas most other languages go to
the other extreme with completely fixed syntax. The trend with metalua,
converge, linq, template haskell, perl6 etc. is to seek a compromise between
these extremes: get as much additional power as possible while minimizing
the software engineering impact (I'm not implying that all of these
languages/dialects will succeed in their endeavor).

There's also an alternative approach, lead by Rubyists, which consists into
building DSLs with runtime semantics, but these DSLs aren't fundamentally
simpler to write, learn and integrate together than static ones IMO.

-- Fabien.

Continue reading on narkive:
Loading...