395
edits
mNo edit summary |
Philosopher (talk | contribs) 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: | ||
< | <syntaxhighlight lang="php"> | ||
if (condition) | if (condition) { | ||
{ | # true block, will be executed if condition is true | ||
} else { | |||
# false block, will be executed if condition is false | |||
} | } | ||
</syntaxhighlight> | |||
</ | |||
To negate the whole thing, use the '''!''' operator: | To negate the whole thing, use the '''!''' operator: | ||
< | <syntaxhighlight lang="php"> | ||
if (!condition) | if (!condition) { | ||
{ | # false block, will be executed if condition is true | ||
} else { | |||
# true block, will be executed if condition is false | |||
} | } | ||
</syntaxhighlight> | |||
</ | |||
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: | ||
< | <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 | ||
} else { | |||
# false block, will be executed if condition is false | |||
} | } | ||
</syntaxhighlight> | |||
</ | |||
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")) { | ||
# true block, will be executed if condition is true | |||
) | } else { | ||
{ | # false block, will be executed if condition is false | ||
} | |||
else { | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 59: | Line 49: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
if ( | if (getprop("/sim/signals/freeze")) { | ||
# true block, will be executed if condition is true | |||
) | } else { | ||
{ | # false block, will be executed if condition is false | ||
} | |||
else { | |||
} | } | ||
</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) { | |||
{ | if(n<0) | ||
{ return -n } | |||
else | |||
{ return n } | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
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 } | |||
</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; | |||
if (foo) | |||
print("1\n"); | |||
else | |||
print("0\n"); | |||
print("this is printed regardless\n") | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 107: | Line 92: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
if (1==2) { | |||
print("wrong"); | print("wrong"); | ||
} else if (1==3) { # NOTE the space between else and if | |||
print("wronger"); | print("wronger"); | ||
} 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": | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
if (1==2) { | |||
print("wrong"); | print("wrong"); | ||
} elsif (1==3) { | |||
print("wronger"); | print("wronger"); | ||
} else { | |||
print("don't know"); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 136: | Line 118: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
if (nil) { | |||
print("This should never be printed"); | print("This should never be printed"); | ||
} 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. | 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 a = nil; | |||
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 | Note that you should always surround multiple conditions within outer parentheses: | ||
<syntaxhighlight lang="php"> | <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> | </syntaxhighlight> | ||
| Line 168: | Line 149: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
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. | 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 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"); | |||
if (altitude_ft == nil) { | |||
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; | |||
</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; | |||
if (a==1) { | |||
do_something() or print("failed"); | |||
} | |||
var do_something = func return 0; | |||
( (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; | |||
( a and do_something() ) or print("failed"); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 231: | Line 210: | ||
<syntaxhighlight lang="php"> | <syntaxhighlight lang="php"> | ||
if (a==1) function_a(); | |||
else | |||
if (a==2) function_b(); | |||
else | |||
if (a==3) function_c(); | |||
else | |||
if (a==4) function_d(); | |||
else | |||
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}; | |||
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: | ||
<syntaxhighlight lang="php" line start="460"> | |||
if (code == "altocumulus_sky"){weather_tiles.set_altocumulus_tile();} | |||
else if (code == "broken_layers") {weather_tiles.set_broken_layers_tile();} | |||
else if (code == "stratus") {weather_tiles.set_overcast_stratus_tile();} | |||
else if (code == "cumulus_sky") {weather_tiles.set_fair_weather_tile();} | |||
else if (code == "gliders_sky") {weather_tiles.set_gliders_sky_tile();} | |||
else if (code == "blue_thermals") {weather_tiles.set_blue_thermals_tile();} | |||
else if (code == "summer_rain") {weather_tiles.set_summer_rain_tile();} | |||
else if (code == "high_pressure_core") {weather_tiles.set_high_pressure_core_tile();} | |||
else if (code == "high_pressure") {weather_tiles.set_high_pressure_tile();} | |||
else if (code == "high_pressure_border") {weather_tiles.set_high_pressure_border_tile();} | |||
else if (code == "low_pressure_border") {weather_tiles.set_low_pressure_border_tile();} | |||
else if (code == "low_pressure") {weather_tiles.set_low_pressure_tile();} | |||
else if (code == "low_pressure_core") {weather_tiles.set_low_pressure_core_tile();} | |||
else if (code == "cold_sector") {weather_tiles.set_cold_sector_tile();} | |||
else if (code == "warm_sector") {weather_tiles.set_warm_sector_tile();} | |||
else if (code == "tropical_weather") {weather_tiles.set_tropical_weather_tile();} | |||
else if (code == "test") {weather_tiles.set_4_8_stratus_tile();} | |||
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: | ||
<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 isFunc = func(f) typeof(f)=='func'; | |||
var hasMethod = func(h,m) contains(h,m) and isFunc; | |||
var callIfAvailable = func(hash, method, unavailable=func{} ) { | |||
var c=hasMethod(hash,makeFuncString(m) ) or unavailable(); | |||
hash[makeFuncString(m)] (); | |||
} | |||
callIfAvailable( weather_tiles,code, func {die("key not found in hash or not a func");} ); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
edits