nesting 4+ loops

Started by eduran, December 10, 2013, 08:44:57 AM

Previous topic - Next topic

eduran

The wiki states that you can only nest up to three loops, but the following code works anyway:
0 ->i
do(10 0)
do(10 0)
do(10 0)
do(10 0)
do(10 0)
<-i add(1) ->i
loop loop loop loop loop
Trace(<-i) # i=100000


Is the wiki wrong? Are there any non-obvious issues connected with nesting loops like that? I'd like to use four nested loops in a script, but am worried that I could run into problems. Or that a future patch could make the script unusable.

Grauniad

There are only 3 loop counters. I, J, K.
A goodnight to all and to all a good night - Goodnight Moon

Grayzzur

#2
As Grauniad said, there are only 3 internal loop variables. If you need access to the 4th or farther out loops from the inner ones, you'll have to save the counter to a variable. At that point you may want to save all loop counters to variables to prevent confusion -- as I is always the inner most loop from the context where it's used, but your saved variable will be global.

So, if you have need to go deeper, you might try something like this:

do(10 0)
I ->a
do(10 0)
I ->b
do(10 0)
I ->c
do(10 0)
I ->d
do(10 0)
I ->e
<-a <-b <-c <-d <-e Trace5
loop
loop
loop
loop
loop


Be aware that there is a limit to the number of instructions that a CRPL Core is allowed to execute each game tick, and at that limit it is cut off. If you have too many loops nested too deeply, you increase your chance to hit that limit. I forget what the limit is... something like 100,000 (500,000?) instructions. That innocent looking set of 5 nested loops with only 10 iterations each pegs 100,000 (10^5 = 100,000).

My question for you would be: What are you trying to do that requires nesting that deeply? Or is it just a rhetorical question?

Edit: Fixed code sample.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

eduran

So the loop variables are the only potential issue? That's good to know.

Quote from: Grayzzur on December 10, 2013, 09:32:04 AM
Be aware that there is a limit to the number of instructions that a CRPL Core is allowed to execute each game tick, and at that limit it is cut off. If you have too many loops nested too deeply, you increase your chance to hit that limit. I forget what the limit is... something like 100,000 (500,000?) instructions. That innocent looking set of 5 nested loops with only 10 iterations each pegs 100,000 (10^5 = 100,000).
I am very aware of that limit, as I already ran into it a couple of times. It's 1,000,000 instructions per frame (CRPL is nice enough to notify you about it via the trace log).

Quote from: Grayzzur on December 10, 2013, 09:32:04 AM
My question for you would be: What are you trying to do that requires nesting that deeply? Or is it just a rhetorical question?
It's connected to pathfinding. One part of that algorithm is way easier to code with a fourth nested loop.

Grauniad

#4
@Grayzzur. I'm not sure your example of preserving loop variables are correct, haven't tested it, but since the compile knows about nested loops, it may (will?) try to assign the variables to the different nested loops. at the point of creating the 4th nested loop, the "I"-value assignment are, as we like to say "undefined", and so will be the assignment of J and K.

Even if it is correct, since nesting >3 loops are not covered under the spec, a revision of CRPL may change that behavior.

Your count of instructions are also wrong - I know you intended it as illustration, but the inner loop has two instructions and I don't know if program flow counts, if it does, then the "do" count for a 3rd.

Each of the successive outer loops also has an assignment instruction as well as the loop instruction. So, I'd say you're closer to 400,000 instructions than 100,000 :)

Edit:

@eduran: If you're trying to do pathfinding for "fun" and to improve your CRPL skills, go ahead. However, I know that Virgil is considering (post Colonial Space) adding CRPL commands for pathfinding and routing. YOu may want to wait with a real map until such a time.

Quote from: eduran on December 10, 2013, 09:55:31 AM
So the loop variables are the only potential issue? That's good to know.

No, that's not the *only* issue. The foremost issue is that it is not within the language specifications, so the behavior is undefined, and whatever it is, it may change to do something internal being reworked. You should not ever rely on undocumented features unless Virgil commits to incorporating them in the specifications.

Edit to retract a "post-before-thought" idiocy.
A goodnight to all and to all a good night - Goodnight Moon

Lord_Farin

Due to the inherently local nature of the counting variables (i.e. calling another function which has a loop should not mess up the indexing variables in the parent routine), one can simply nest in "blocks of three" by calling a function innerNest which unlocks three new levels of nesting (one probably wants to pass the indexing variables as parameters to innerNest).

Perhaps you can even mimic the anonymous functions from e.g. Java by declaring the function inline, but I haven't tried this.

The main advantage of this approach is that it is guaranteed to work, as it is (or seems to me to be) entirely contained within the current CRPL specification.
Behold, Nexus! Looketh skywards, for thy obliteration thence nighs, my foul enemy!

Grayzzur

#6
@eduran @Grauniad: That's why I said "iterations" and not "instructions." :)

I've fixed my code sample. I had the loop counter wrong, it should just be "I" not "<-I". I is the inner counter even with deeply nested loops. You're right that it's not documented, but I don't think that it would be changed to have I not be the innermost counter. Any changes would affect the outer loops, I would think.

Actually, I think my inner loop counts as 8 instructions, and each outer loop has 2 of it's own. Every push to the stack, every assignment, every command is an instruction. Still, when I ran a sample, it made it to "9 9 9 9 9" on the trace output, though I definitely exceeded the trace log window's buffer.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

eduran

Quote from: Grauniad on December 10, 2013, 09:57:04 AM
@eduran: If you're trying to do pathfinding for "fun" and to improve your CRPL skills, go ahead. However, I know that Virgil is considering (post Colonial Space) adding CRPL commands for pathfinding and routing. YOu may want to wait with a real map until such a time.
As strange as it may sound, but having fun is the main reason why I make maps for CW3. I love programming and since I don't get to do it on the job I jump at every opportunity to code something in my free time.

Quote from: Grayzzur on December 10, 2013, 10:34:15 AM
@eduran: That's why I said "iterations" and not "instructions."
Is that meant to be directed at Lord_Farin instead of me? Seems to fit his post a lot better than mine.


Grayzzur

Directed at Grauniad's counting, actually. Somehow those two posts blended together the first time I read them. I'm off to get more coffee.   ;D
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

thepenguin

Quote from: Grauniad on December 10, 2013, 09:57:04 AM
No, that's not the *only* issue. The foremost issue is that it is not within the language specifications, so the behavior is undefined, and whatever it is, it may change to do something internal being reworked. You should not ever rely on undocumented features unless Virgil commits to incorporating them in the specifications.
And yet the program works.  It works.  It may not be good procedure, but the thing works.  I don't object to the "should not", but I do object to the "ever".

I have also never seen a language with a nuttier control flow than CRPL.  These structures are the most illogical things I have ever seen in a programming language (position-relative loop variable names, really?) with the possible exception of Python...
We have become the creeper...

Grayzzur

Quote from: thepenguin on December 10, 2013, 11:05:10 PM
I have also never seen a language with a nuttier control flow than CRPL.  These structures are the most illogical things I have ever seen in a programming language (position-relative loop variable names, really?) with the possible exception of Python...
Really? It's a basic RPN-style stack-based language (Reverse Polish Notation). Lots of HP calculators use a similar language. I actually avoid using the warp operator in my own code, as I can follow the flow better.
"Fate. It protects fools, little children, and ships named 'Enterprise.'" -William T. Riker

thepenguin

Quote from: Grayzzur on December 11, 2013, 11:48:50 AM
Really? It's a basic RPN-style stack-based language (Reverse Polish Notation). Lots of HP calculators use a similar language. I actually avoid using the warp operator in my own code, as I can follow the flow better.
I don't mean the backwards-ness of the commands themselves.  I can follow that (I am also not a user of the warp).

The problem is with (if/do/for/loop/while/functions/some variable stuff/loop pointers).
We have become the creeper...

knucracker

CRPL definitely isn't forth, but it borrows its do/loop from it (along with 'I' and 'J'.  I added a 'K'):
http://www.forth.com/starting-forth/sf6/sf6.html

Some other things I got from RPL, some I made up because they fell out of the stack structure implementation.