Nasal Loops: Difference between revisions

Jump to navigation Jump to search
m
Syntax highlight and remove (extraneous) heading
m (Syntax highlight and remove (extraneous) heading)
Line 1: Line 1:
{{Nasal Navigation}}
{{Nasal Navigation}}
== Loops ==


Nasal has several ways to implement an iteration.
Nasal has several ways to implement an iteration.


===for, while, foreach, and forindex loops===
== for, while, foreach, and forindex loops ==
Nasal's looping constructs are mostly C-like:
Nasal's looping constructs are mostly C-like:


for(var i=0; i < 3; i = i+1) {
<syntaxhighlight lang="php">
  # loop body
for(var i=0; i < 3; i = i+1) {
  }
# loop body
}


while (condition) {
while (condition) {
  # loop body
  # loop body
}
}
</syntaxhighlight>


The differences are that there is no do{}while(); construct, and there is a foreach, which takes a local variable name as its first argument and a vector as its second:
The differences are that there is no do{}while(); construct, and there is a foreach, which takes a local variable name as its first argument and a vector as its second:


  foreach(elem; list1) { doSomething(elem); }  # NOTE: the delimiter is a SEMICOLON ;
<syntaxhighlight lang="php">
foreach(elem; list1) { doSomething(elem); }  # NOTE: the delimiter is a SEMICOLON ;
</syntaxhighlight>


The hash/vector index expression is an lvalue that can be assigned as well as inspected:
The hash/vector index expression is an lvalue that can be assigned as well as inspected:


  foreach(light; lights) { lightNodes[light] = propertyPath; }
<syntaxhighlight lang="php">
foreach(light; lights) { lightNodes[light] = propertyPath; }
</syntaxhighlight>


To walk through all elements of a hash, for a foreach loop on the keys of they hash.  Then you call pull up the values of the hash using the key.  Example:
To walk through all elements of a hash, for a foreach loop on the keys of they hash.  Then you call pull up the values of the hash using the key.  Example:


myhash= {first: 1000, second: 250, third: 25.2 };
<syntaxhighlight lang="php">
foreach (var i; keys (myhash)) {
myhash= {first: 1000, second: 250, third: 25.2 };
  #multiply each value by 2:
foreach (var i; keys (myhash)) {
  myhash[i] *= 2;  
  #multiply each value by 2:
  #print the key and new value:
  myhash[i] *= 2;  
  print (i, ": ", myhash[i]);
  #print the key and new value:
}
  print (i, ": ", myhash[i]);
}
</syntaxhighlight>


There is also a "forindex", which is like foreach except that it assigns the index of each element, instead of the value, to the loop variable.
There is also a "forindex", which is like foreach except that it assigns the index of each element, instead of the value, to the loop variable.


forindex(i; list1) { doSomething(list1[i]); }
<syntaxhighlight lang="php">
forindex(i; list1) { doSomething(list1[i]); }
</syntaxhighlight>


Also, braceless blocks work for loops equally well:
Also, braceless blocks work for loops equally well:


var c=0;
<syntaxhighlight lang="php">
while( c<5 )
var c=0;
while( c<5 )
   print( c+=1 );
   print( c+=1 );
print("end of loop\n");
print("end of loop\n");
</syntaxhighlight>


===settimer loops===
== settimer loops ==
Loops using <tt>while</tt>, <tt>for</tt>, <tt>foreach</tt>, and <tt>forindex</tt> block all of FlightGear's subsystems that run in the main thread, and can, thus, only be used for instantaneous operations that don't take too long.  
Loops using <tt>while</tt>, <tt>for</tt>, <tt>foreach</tt>, and <tt>forindex</tt> block all of FlightGear's subsystems that run in the main thread, and can, thus, only be used for instantaneous operations that don't take too long.  


For operations that should continue over a longer period, one needs a non-blocking solution. This is done by letting functions call themselves after a timed delay:  
For operations that should continue over a longer period, one needs a non-blocking solution. This is done by letting functions call themselves after a timed delay:  


var loop = func {
<syntaxhighlight lang="php">
    print("this line appears once every two seconds");
var loop = func {
    settimer(loop, 2);
    print("this line appears once every two seconds");
}
    settimer(loop, 2);
}
loop();        # start loop
 
loop();        # start loop
</syntaxhighlight>


Note that the <tt>settimer</tt> function expects a ''function object'' (<tt>loop</tt>), not a function call (<tt>loop()</tt>) (though it is possible to make a function call return a function object--an advanced functional programming technique that you won't need to worry about if you're just getting started with Nasal).  
Note that the <tt>settimer</tt> function expects a ''function object'' (<tt>loop</tt>), not a function call (<tt>loop()</tt>) (though it is possible to make a function call return a function object--an advanced functional programming technique that you won't need to worry about if you're just getting started with Nasal).  
Line 62: Line 73:
The fewer code FlightGear has to execute, the better, so it is desirable to run loops only when they are needed. But how does one stop a loop? A once triggered timer function can't be revoked. But one can let the loop function check an outside variable and refuse calling itself, which makes the loop chain die off:
The fewer code FlightGear has to execute, the better, so it is desirable to run loops only when they are needed. But how does one stop a loop? A once triggered timer function can't be revoked. But one can let the loop function check an outside variable and refuse calling itself, which makes the loop chain die off:


<pre>
<syntaxhighlight lang="php">
var running = 1;
var running = 1;
var loop = func {
var loop = func {
    if (running) {
    if (running) {
        print("this line appears once every two seconds");
        print("this line appears once every two seconds");
        settimer(loop, 2);
        settimer(loop, 2);
    }
    }
}
}
 
loop();        # start loop ...
loop();        # start loop ...
...
...
running = 0;  # ... and let it die
running = 0;  # ... and let it die
</pre>
</syntaxhighlight>


== Loop Identifiers ==
=== Loop Identifiers ===


Unfortunately, this method is rather unreliable. What if the loop is "stopped" and a new instance immediately started again? Then the ''running'' variable would be ''1'' again, and a pending old loop call, which should really finish this chain, would happily continue. And the new loop chain would start, too, so that we would end up with two loop chains.
Unfortunately, this method is rather unreliable. What if the loop is "stopped" and a new instance immediately started again? Then the ''running'' variable would be ''1'' again, and a pending old loop call, which should really finish this chain, would happily continue. And the new loop chain would start, too, so that we would end up with two loop chains.
Line 99: Line 110:
Beginning with FlightGear 2.11+ you should consider using the '''maketimer()''' API instead.
Beginning with FlightGear 2.11+ you should consider using the '''maketimer()''' API instead.


[[List_of_Nasal_extension_functions#settimer.28.29|More information about the settimer function is below]]
[[List_of_Nasal_extension_functions#settimer.28.29|More information about the settimer function]]
395

edits

Navigation menu