Iteration loops have the form:
IM IN YR <label> <operation> YR <variable> [TIL|WILE <expression>]
<code block>
IM OUTTA YR <label>
Where <operation> may be UPPIN (increment by one), NERFIN (decrement by one), or any unary function. That operation/function is applied to the <variable>, which is temporary, and local to the loop. The TIL <expression> evaluates the expression as a TROOF: if it evaluates as FAIL, the loop continues once more, if not, then loop execution stops, and continues after the matching IM OUTTA YR <label>. The WILE <expression> is the converse: if the expression is WIN, execution continues, otherwise the loop exits.
My gripe with the spec is the combination of:
As I understand it, this means it has to start at 0.
While that's mostly ok for most uses of UPPIN
, it's totally off for most (my) intended uses of NERFIN
. My most common uses of a decrementing loop variable in other languages are the "repeat n times (n not re-used)" idiom and string operations, which wouldn't be a good idea in LOLCODE anyway.
Is it possible to use NERFIN
to get a loop decrement from n to 1 or 0 in a way that's less verbose than the equivalents with UPPIN
or the operationless forms of looping?
Printing 5 4 3 2 1 with the UPPIN
variant:
IM IN YR LOOPZ UPPIN YR COWNTR TIL BOTH SAEM COWNTR AN 5
VISIBLE DIFF OF 5 AN COWNTR
IM OUTTA YR LOOPZ
Pros: concise.
Cons: actual loop variable is not accessible directly.
With the operationless variant:
I HAS A COWNTR ITZ 5
IM IN YR LOOPZ
VISIBLE COWNTR
COWNTR R DIFF OF COWNTR AN 1
BOTH SAEM COWNTR AN 0, O RLY?
YA RLY, GTFO, OIC
IM OUTTA YR LOOPZ
Pros: loop variable is directly available.
Cons: longer.
Best I can get with NERFIN
:
IM IN YR LOOPZ NERFIN YR COWNTR TIL BOTH SAEM COWNTR AN -5
VISIBLE SUM OF 5 AN COWNTR
IM OUTTA YR LOOPZ
Pros: err... uses NERFIN
?
Cons: loop variable isn't directly accessible; less readable (hah!) than the UPPIN
variant; no gain in verbosity.
Is it possible to use NERFIN
to get a loop decrement from n to 1 or 0 in a way that's less verbose than the equivalents with UPPIN
or the operationless forms of looping?
I'm using the lci interpreter at language specification level 1.2.
There was design discussion from 2007 on this exact topic. Consensus at the time seemed to suggest adding a FROM
as a solution the working group wanted fast-tracked into 1.2:
http://forum.lolcode.com/viewtopic.php?pid=2484
The issue was tabled and didn't make it in to the 1.2 spec. However, it is apparently in the 1.3 specification:
http://lolcode.com/proposals/1.3/loop2
Still in the works, though. I checked and it is not in the "future" branch of the repository yet. We can see this by looking into the loop interpreter code. As of 8/24/2011 (in revision 72c983d0667d4d650657e1b7c5f4c7054096b0dd) it still always initially assigns the loop variable a NUMBR
of 0:
https://github.com/justinmeza/lci/blob/72c983d0667d4d650657e1b7c5f4c7054096b0dd/interpreter.c#L3434
However, even with the old spec, it should theoretically be possible to use a TROOF
in combination with a test against -1 to allow for a relatively clean form of counting down from 5 to 0:
BTW countdown-test.lol
CAN HAS STDIO?
HAI 1.2
HOW DUZ I COUNTDOWN YR BOWNDZ
I HAS A FIRSTIES
FIRSTIES R WIN
IM IN YR LOOPZ NERFIN YR COWNTR TIL BOTH SAEM COWNTR AN -1
FIRSTIES
O RLY?
YA RLY
COWNTR R BOWNDZ
FIRSTIES R FAIL
OIC
VISIBLE COWNTR
IM OUTTA YR LOOPZ
IF U SAY SO
COUNTDOWN 5
KTHXBYE
Unfortunately, there is an "efficiency hack" which prevents code inside a loop from modifying the loop variable using R
:
https://github.com/justinmeza/lci/blob/a6ef5811e8eb98935a16600b799bccbe4adffdde/interpreter.c#L3408
Yet as this seems to be a bug in the code as opposed to an omission in the spec, it's more likely to get fixed in advance of the 1.3 release. Patching interpreter.c
to say if (0 && stmt->update->type == ET_OP)
makes the code for countdown-test.lol
run as expected. It may be a suitable interim solution for existing 1.2 LOLCODE deployments if you don't have to share code with unpatched installations.