Nasal Conditionals: Difference between revisions

Jump to navigation Jump to search
m
<syntaxhighlight> and tabulations and style
mNo edit summary
m (<syntaxhighlight> and tabulations and style)
Line 4: Line 4:
Sometimes you may only want to execute certain portions of your code, depending on conditions. This can be accomplished in several ways. One of the most straightforward ways  being an '''if''' expression, which  has the form:
Sometimes you may only want to execute certain portions of your code, depending on conditions. This can be accomplished in several ways. One of the most straightforward ways  being an '''if''' expression, which  has the form:


<pre>
<syntaxhighlight lang="php">
if (condition)  
if (condition) {
{
    # true block, will  be executed if condition is true
# true block, will  be executed if condition is true
} else {
    # false block, will be executed if condition is false
}
}
else {
</syntaxhighlight>
# false block, will be executed if condition is false
}
</pre>


To negate the whole thing, use the '''!''' operator:
To negate the whole thing, use the '''!''' operator:


<pre>
<syntaxhighlight lang="php">
if (!condition)  
if (!condition) {
{
    # false block, will  be executed if condition is true
# false block, will  be executed if condition is true
} else {
    # true block, will be executed if condition is false
}
}
else {
</syntaxhighlight>
# true block, will be executed if condition is false
}
</pre>


In both examples, the '''condition''' variable is just a placeholder, it could be a variable named '''condition''', but it could also be a more complex expression, such as a '''getprop''' call for example:
In both examples, the '''condition''' variable is just a placeholder, it could be a variable named '''condition''', but it could also be a more complex expression, such as a '''getprop''' call for example:


<pre>
<syntaxhighlight lang="php">
var condition = getprop("/sim/signals/freeze");
var condition = getprop("/sim/signals/freeze");


if (condition)  
if (condition) {
{
    # true block, will  be executed if condition is true
# true block, will  be executed if condition is true
} else {
    # false block, will be executed if condition is false
}
}
else {
</syntaxhighlight>
# false block, will be executed if condition is false
}
</pre>


The same thing could be accomplished by using a call to getprop() as part of the condition:
The same thing could be accomplished by using a call to getprop() as part of the condition:
Line 44: Line 38:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
if (
if (var condition = getprop("/sim/signals/freeze")) {
var condition = getprop("/sim/signals/freeze")
    # true block, will  be executed if condition is true
)  
} else {
{
    # false block, will be executed if condition is false
# true block, will  be executed if condition is true
}
else {
# false block, will be executed if condition is false
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 59: Line 49:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
if (
if (getprop("/sim/signals/freeze")) {
getprop("/sim/signals/freeze")
    # true block, will  be executed if condition is true
)  
} else {
{
    # false block, will be executed if condition is false
# true block, will  be executed if condition is true
}
else {
# false block, will be executed if condition is false
}
}
</syntaxhighlight>
</syntaxhighlight>
Line 74: Line 60:


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 ?: (ternary operator) does in C.  
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 ?: (ternary operator) does in C.  
The last semicolon in a code block is optional, to make this prettier
The last semicolon in a code block is optional, to make this prettier:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var abs = func(n)  
var abs = func(n) {  
{  
    if(n<0)  
  if(n<0)  
    { return -n }
  { return -n }  
    else  
  else  
    { return n }
  { return n }  
}
}
</syntaxhighlight>
</syntaxhighlight>


But for those who don't like typing, the ternary operator works like you expect:
And for those who don't like typing, the ternary operator works like you expect:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var abs = func(n) { n < 0 ? -n : n }
var abs = func(n) { n < 0 ? -n : n }
</syntaxhighlight>
</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:
In addition, Nasal supports braceless blocks, like they're known from C/C++ and other languages. Basically, the block ends with a semicolon, instead of being encapsulated inside a <tt>{</tt>/<tt>}</tt> pair. 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">
<syntaxhighlight lang="php">
var foo=1;
var foo=1;
if (foo)
if (foo)
  print("1\n");
    print("1\n");
else
else
  print("0\n");
    print("0\n");
print("this is printed regardless\n")
print("this is printed regardless\n")
</syntaxhighlight>
</syntaxhighlight>


Line 107: Line 92:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  if (1==2) {
if (1==2) {
     print("wrong");
     print("wrong");
  } else if (1==3) { # NOTE the space between else and if
} else if (1==3) { # NOTE the space between else and if
     print("wronger");
     print("wronger");
  } else {
} else {
     print("don't know");
     print("don't know");
  }
}
</syntaxhighlight>
</syntaxhighlight>
which produces the expected output of <code>don't know</code>.


Instead of "else if", you can also use the shorter equivalent form "elsif".
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">
<syntaxhighlight lang="php">
  if (1==2) {
if (1==2) {
     print("wrong");
     print("wrong");
  } elsif (1==3) {  
} elsif (1==3) {  
     print("wronger");
     print("wronger");
  } else {
} else {
    print("don't know");
  print("don't know");
  }
}
</syntaxhighlight>
</syntaxhighlight>


Line 136: Line 118:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
  if (nil) {
if (nil) {
     print("This should never be printed");
     print("This should never be printed");
  } else {
} else {
     print("This will be printed, because nil is always false");
     print("This will be printed, because nil is always false");
  };
};
</syntaxhighlight>
</syntaxhighlight>






Nasal's binary boolean operators are "and" and "or", unlike C. unary not is still "!" however.  
Nasal's binary boolean operators are "and" and "or", unlike C. Unary not is still "!" however. They short-circuit like you expect:
They short-circuit like you expect


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var toggle = 0;
var toggle = 0;
var a = nil;
var a = nil;
if(a and a.field == 42) {
if (a != nil and a.field == 42) {
     toggle = !toggle; # doesn't crash when a is nil
     toggle = !toggle; # doesn't crash when a is nil
}
}
</syntaxhighlight>
</syntaxhighlight>


Note that you should always surround multiple conditions within outer parentheses, e.g.:
Note that you should always surround multiple conditions within outer parentheses:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
if (1) do_something();
if (1) do_something();
if (1 and 1) do_something();
if (1 and 1) do_something();
if ( (1) and (1) ) do_something();
if ( (1) and (1) ) do_something();
if ( (1) or (0) ) do_something();
if ( (1) or (0) ) do_something();
</syntaxhighlight>
</syntaxhighlight>


Line 168: Line 149:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var altitude = getprop("/position/altitude-ft") or 0.00;
var altitude = getprop("/position/altitude-ft") or 0.00;
</syntaxhighlight>
</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.
Basically this will first execute the getprop() call and if it doesn't return "true" (i.e. if it isn't zero or 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).
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).
Line 180: Line 161:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var x=getprop("/velocities/airspeed-kts") or 0.00; # to ensure that x is always valid number
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
var foo = 10*3.1*x; # ... for this computation
</syntaxhighlight>
</syntaxhighlight>


Line 189: Line 170:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var altitude_ft = getprop("/position/altitude-ft");
var altitude_ft = getprop("/position/altitude-ft");
if (altitude_ft == nil) {
if (altitude_ft == nil) {
  altitude_ft = 0.0;
    altitude_ft = 0.0;
}
}
</syntaxhighlight>
</syntaxhighlight>


Line 198: Line 179:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var altitude_ft = getprop("/position/altitude-ft") or 0.00;
var altitude_ft = getprop("/position/altitude-ft") or 0.00;
</syntaxhighlight>
</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.
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.
Line 210: Line 189:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var do_something = func return 0;
var do_something = func return 0;
if (a==1) {
if (a==1) {
  do_something() or print("failed");
    do_something() or print("failed");
}
}


var do_something = func return 0;
var do_something = func return 0;
( (a==1) and do_something() ) or print("failed");
( (a==1) and do_something() ) or print("failed");
</syntaxhighlight>
</syntaxhighlight>


Line 222: Line 201:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var do_something = func return 0;
var do_something = func return 0;
( a and do_something() ) or print("failed");
( a and do_something() ) or print("failed");
</syntaxhighlight>
</syntaxhighlight>


Line 231: Line 210:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
    if (a==1) function_a();
if (a==1) function_a();
    else
else
    if (a==2) function_b();
if (a==2) function_b();
    else
else
    if (a==3) function_c();
if (a==3) function_c();
    else
else
    if (a==4) function_d();
if (a==4) function_d();
    else
else
    if (a==5) function_e();
if (a==5) function_e();
</syntaxhighlight>
</syntaxhighlight>


Line 245: Line 224:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
    var mapping = {1:function_a, 2:function_b, 3:function_c, 4:function_d,5:function_e};
var mapping = {1:function_a, 2:function_b, 3:function_c, 4:function_d,5:function_e};
    mapping[a] ();
mapping[a] ();
</syntaxhighlight>
</syntaxhighlight>


Line 253: Line 232:
Next, you can actually call the function by appending a list of function arguments (empty parentheses for no args) to the hash lookup.
Next, you can actually call the function by appending a list of function arguments (empty parentheses for no args) to the hash lookup.


Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider:
Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider this extract from weather_tile_management.nas:


    # weather_tile_management.nas
<syntaxhighlight lang="php" line start="460">
    460        if (code == "altocumulus_sky"){weather_tiles.set_altocumulus_tile();}
if (code == "altocumulus_sky"){weather_tiles.set_altocumulus_tile();}
    461        else if (code == "broken_layers") {weather_tiles.set_broken_layers_tile();}
else if (code == "broken_layers") {weather_tiles.set_broken_layers_tile();}
    462        else if (code == "stratus") {weather_tiles.set_overcast_stratus_tile();}
else if (code == "stratus") {weather_tiles.set_overcast_stratus_tile();}
    463        else if (code == "cumulus_sky") {weather_tiles.set_fair_weather_tile();}
else if (code == "cumulus_sky") {weather_tiles.set_fair_weather_tile();}
    464        else if (code == "gliders_sky") {weather_tiles.set_gliders_sky_tile();}
else if (code == "gliders_sky") {weather_tiles.set_gliders_sky_tile();}
    465        else if (code == "blue_thermals") {weather_tiles.set_blue_thermals_tile();}
else if (code == "blue_thermals") {weather_tiles.set_blue_thermals_tile();}
    466        else if (code == "summer_rain") {weather_tiles.set_summer_rain_tile();}
else if (code == "summer_rain") {weather_tiles.set_summer_rain_tile();}
    467        else if (code == "high_pressure_core") {weather_tiles.set_high_pressure_core_tile();}
else if (code == "high_pressure_core") {weather_tiles.set_high_pressure_core_tile();}
    468        else if (code == "high_pressure") {weather_tiles.set_high_pressure_tile();}
else if (code == "high_pressure") {weather_tiles.set_high_pressure_tile();}
    469        else if (code == "high_pressure_border") {weather_tiles.set_high_pressure_border_tile();}
else if (code == "high_pressure_border") {weather_tiles.set_high_pressure_border_tile();}
    470        else if (code == "low_pressure_border") {weather_tiles.set_low_pressure_border_tile();}
else if (code == "low_pressure_border") {weather_tiles.set_low_pressure_border_tile();}
    471        else if (code == "low_pressure") {weather_tiles.set_low_pressure_tile();}
else if (code == "low_pressure") {weather_tiles.set_low_pressure_tile();}
    472        else if (code == "low_pressure_core") {weather_tiles.set_low_pressure_core_tile();}
else if (code == "low_pressure_core") {weather_tiles.set_low_pressure_core_tile();}
    473        else if (code == "cold_sector") {weather_tiles.set_cold_sector_tile();}
else if (code == "cold_sector") {weather_tiles.set_cold_sector_tile();}
    474        else if (code == "warm_sector") {weather_tiles.set_warm_sector_tile();}
else if (code == "warm_sector") {weather_tiles.set_warm_sector_tile();}
    475        else if (code == "tropical_weather") {weather_tiles.set_tropical_weather_tile();}
else if (code == "tropical_weather") {weather_tiles.set_tropical_weather_tile();}
    476        else if (code == "test") {weather_tiles.set_4_8_stratus_tile();}
else if (code == "test") {weather_tiles.set_4_8_stratus_tile();}
    477        else ...
else ...
</syntaxhighlight>


While this is not a very complex or huge block of code, it is an excellent example for very good naming conventions used already, because the consistency of naming variables and functions can pay off easily here, with just some very small changes, you can already reduce the whole thing to a hash lookup like this:
While this is not a very complex or huge block of code, it is an excellent example for very good naming conventions used already, because the consistency of naming variables and functions can pay off easily here, with just some very small changes, you can already reduce the whole thing to a hash lookup like this:
Line 287: Line 267:
But these are very simple changes to do (just renaming these functions to match the existing conventions). When you do that, you can easily replace such huge IF statements and replace them with a single hash lookup and function call:
But these are very simple changes to do (just renaming these functions to match the existing conventions). When you do that, you can easily replace such huge IF statements and replace them with a single hash lookup and function call:


hash[key] (arguments...);
<syntaxhighlight lang="php">
hash[key] (arguments...);
</syntaaxhighlight>


For example, consider:
For example, consider:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var makeFuncString = func(c) return tolower("set_"~c~"_tile");
var makeFuncString = func(c) return tolower("set_"~c~"_tile");
var isFunc = func(f) typeof(f)=='func';
var isFunc = func(f) typeof(f)=='func';
var hasMethod = func(h,m) contains(h,m) and isFunc;
var hasMethod = func(h,m) contains(h,m) and isFunc;
var callIfAvailable = func(hash, method, unavailable=func{} ) {
var callIfAvailable = func(hash, method, unavailable=func{} ) {
  var c=hasMethod(hash,makeFuncString(m) ) or unavailable();
    var c=hasMethod(hash,makeFuncString(m) ) or unavailable();
  hash[makeFuncString(m)] ();
    hash[makeFuncString(m)] ();
}
}
callIfAvailable( weather_tiles,code, func {die("key not found in hash or not a func");} );
callIfAvailable( weather_tiles,code, func {die("key not found in hash or not a func");} );
</syntaxhighlight>
</syntaxhighlight>
395

edits

Navigation menu