Nasal scripting language: Difference between revisions

Jump to navigation Jump to search
Line 234: Line 234:


In addition, it is worth noting that the Nasal/FlightGear APIs cannot currently be considered to be thread safe, this mean that -at least for now- the explicit use of pure Nasal space variables is the only way to exploit possible parallelism in your code by making use of threads.
In addition, it is worth noting that the Nasal/FlightGear APIs cannot currently be considered to be thread safe, this mean that -at least for now- the explicit use of pure Nasal space variables is the only way to exploit possible parallelism in your code by making use of threads.
== Conditionals ==
Nasal has no "statements", which means that any expression can appear in any context. This means that you can use an if/else clause to do what the ?: does in C.
The last semicolon in a code block is optional, to make this prettier
<syntaxhighlight lang="php">
var abs = func(n) { if(n<0) { -n } else { n } }
</syntaxhighlight>
But for those who don't like typing, the ternary operator works like you expect:
<syntaxhighlight lang="php">
var abs = func(n) { n < 0 ? -n : n }
</syntaxhighlight>
In addition, Nasal supports braceless blocks, like they're known from C/C++ and other languages. This means basically that the first statement (expression) after a conditional is evaluated if the condition is true, otherwise it will be ignored:
<syntaxhighlight lang="php">
var foo=1;
if (foo)
  print("1\n");
else
  print("0\n");
print("this is printed regardless\n")
</syntaxhighlight>
Instead of a switch statement one can use
<syntaxhighlight lang="php">
  if (1==2) {
    print("wrong");
  } else if (1==3) { # NOTE the space between else and if
    print("wronger");
  } else {
    print("don't know");
  }
</syntaxhighlight>
Instead of "else if", you can also use the shorter equivalent form "elsif".
which produces the expected output of <code>don't know</code>
In addition to "else if", Nasal also supports a short-hand version of it, called "elsif", which is semantically identical:
<syntaxhighlight lang="php">
  if (1==2) {
    print("wrong");
  } elsif (1==3) {
    print("wronger");
  } else {
    print("don't know");
  }
</syntaxhighlight>
The <tt>nil</tt> logic is actually quite logical, let's just restate the obvious:
<syntaxhighlight lang="php">
  if (nil) {
    print("This should never be printed");
  } else {
    print("This will be printed, because nil is always false");
  };
</syntaxhighlight>
Nasal's binary boolean operators are "and" and "or", unlike C. unary not is still "!" however.
They short-circuit like you expect
<syntaxhighlight lang="php">
var toggle = 0;
var a = nil;
if(a and a.field == 42) {
    toggle = !toggle; # doesn't crash when a is nil
}
</syntaxhighlight>
Note that you should always surround multiple conditions within outer parentheses, e.g.:
<syntaxhighlight lang="php">
if (1) do_something();
if (1 and 1) do_something();
if ( (1) and (1) ) do_something();
if ( (1) or (0) ) do_something();
</syntaxhighlight>
Nasal's binary boolean operators can also be used to default expressions to certain values:
<syntaxhighlight lang="php">
var altitude = getprop("/position/altitude-ft") or 0.00;
</syntaxhighlight>
Basically this will first execute the getprop() call and if it doesn't return "true" (i.e. non zero/nil), it will instead use 0.00 as the value for the altitude variable.
Regarding boolean operators like and/or: This is working because they "short circuit", i.e. in an OR comparison, the remaining checks are NEVER done IF any single of the previous checks is true (1), because that'll suffice to satisfy the OR expression (i.e. knowing that a single check evaluates to true).
Similarly, an "and" expression will inevitably need to do ALL "and" checks in order to evaluate the whole expression.
At first, this may seem pretty complex and counter-intuitive - but it's important to keep this technique in mind, especially for variables that are later on used in calcuations:
<syntaxhighlight lang="php">
var x=getprop("/velocities/airspeed-kts") or 0.00; # to ensure that x is always valid number
var foo= 10*3.1*x; # ... for this computation
</syntaxhighlight>
So this is to ensure that invalid property tree state does not mess up the calculations done in Nasal by defaulting x to 0.00, i.e. a valid numeric value.
Bottom line being, using "or" to default a variable to a given value is a short and succinct way to avoid otherwise elaborate checks, e.g. compare:
<syntaxhighlight lang="php">
var altitude_ft = getprop("/position/altitude-ft");
if (altitude_ft == nil) {
  altitude_ft = 0.0;
}
</syntaxhighlight>
versus:
<syntaxhighlight lang="php">
var altitude_ft = getprop("/position/altitude-ft") or 0.00;
</syntaxhighlight>
Basically: whenever you read important state from the property tree that you'll use in calculations, it's a good practice to default the value to some sane value.
But this technique isn't really specific to getprop (or any other library call).
Nasal is a language that has no statements, it's all about EXPRESSIONS. So you can put things in pretty much arbitrary places.
<syntaxhighlight lang="php">
var do_something = func return 0;
if (a==1) {
  do_something() or print("failed");
}
var do_something = func return 0;
( (a==1) and do_something() ) or print("failed");
</syntaxhighlight>
In a boolean comparison, 1 always means "true" while 0 always means "false". For instance, ANY comparison with if x ==1 can be abbreviated to if (x), because the ==1 check is implictly done:
<syntaxhighlight lang="php">
var do_something = func return 0;
( a and do_something() ) or print("failed");
</syntaxhighlight>


== Using Hashs to map keys to functions ==
== Using Hashs to map keys to functions ==

Navigation menu