4,400
edits
m (make condition less abstract) |
m (Use Nasal highlighter) |
||
| 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=" | <syntaxhighlight lang="nasal"> | ||
var condition=1; # this evaluates to boolean true | var condition=1; # this evaluates to boolean true | ||
if (condition) { | if (condition) { | ||
| Line 15: | Line 15: | ||
To negate the whole thing, use the '''!''' operator: | To negate the whole thing, use the '''!''' operator: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
var condition=1; # boolean true | var condition=1; # boolean true | ||
if (!condition) { | if (!condition) { | ||
| Line 26: | Line 26: | ||
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=" | <syntaxhighlight lang="nasal"> | ||
var condition = getprop("/sim/signals/freeze"); | var condition = getprop("/sim/signals/freeze"); | ||
| Line 39: | Line 39: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (var condition = getprop("/sim/signals/freeze")) { | if (var condition = getprop("/sim/signals/freeze")) { | ||
# true block, will be executed if condition is true | # true block, will be executed if condition is true | ||
| Line 50: | Line 50: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (getprop("/sim/signals/freeze")) { | if (getprop("/sim/signals/freeze")) { | ||
# true block, will be executed if condition is true | # true block, will be executed if condition is true | ||
| Line 63: | Line 63: | ||
* '''or''' | * '''or''' | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
var condition = (1==1 and 2==2 and 3==3) or (4!=5 and !0); | var condition = (1==1 and 2==2 and 3==3) or (4!=5 and !0); | ||
if (condition) { | if (condition) { | ||
| Line 78: | Line 78: | ||
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=" | <syntaxhighlight lang="nasal"> | ||
var abs = func(n) { | var abs = func(n) { | ||
if(n<0) | if(n<0) | ||
| Line 89: | Line 89: | ||
And 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=" | <syntaxhighlight lang="nasal"> | ||
var abs = func(n) { n < 0 ? -n : n } | var abs = func(n) { n < 0 ? -n : n } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 95: | Line 95: | ||
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: | 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=" | <syntaxhighlight lang="nasal"> | ||
var foo=1; | var foo=1; | ||
if (foo) | if (foo) | ||
| Line 107: | Line 107: | ||
Instead of a switch statement one can use | Instead of a switch statement one can use | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (1==2) { | if (1==2) { | ||
print("wrong"); | print("wrong"); | ||
| Line 120: | Line 120: | ||
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=" | <syntaxhighlight lang="nasal"> | ||
if (1==2) { | if (1==2) { | ||
print("wrong"); | print("wrong"); | ||
| Line 133: | Line 133: | ||
The <tt>nil</tt> logic is actually quite logical, let's just restate the obvious: | The <tt>nil</tt> logic is actually quite logical, let's just restate the obvious: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (nil) { | if (nil) { | ||
print("This should never be printed"); | print("This should never be printed"); | ||
| Line 145: | Line 145: | ||
Nasal's binary boolean operators are "and" and "or", unlike C. Unary not is still "!" however. They short-circuit like you expect: | Nasal's binary boolean operators are "and" and "or", unlike C. Unary not is still "!" however. They short-circuit like you expect: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
var toggle = 0; | var toggle = 0; | ||
var a = nil; | var a = nil; | ||
| Line 155: | Line 155: | ||
Note that you should always surround multiple conditions within outer parentheses: | Note that you should always surround multiple conditions within outer parentheses: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (1) do_something(); | if (1) do_something(); | ||
if (1 and 1) do_something(); | if (1 and 1) do_something(); | ||
| Line 164: | Line 164: | ||
Nasal's binary boolean operators can also be used to default expressions to certain values: | Nasal's binary boolean operators can also be used to default expressions to certain values: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
var altitude = getprop("/position/altitude-ft") or 0.00; | var altitude = getprop("/position/altitude-ft") or 0.00; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 176: | Line 176: | ||
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: | 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=" | <syntaxhighlight lang="nasal"> | ||
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 | ||
| Line 185: | Line 185: | ||
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: | 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=" | <syntaxhighlight lang="nasal"> | ||
var altitude_ft = getprop("/position/altitude-ft"); | var altitude_ft = getprop("/position/altitude-ft"); | ||
if (altitude_ft == nil) { | if (altitude_ft == nil) { | ||
| Line 194: | Line 194: | ||
versus: | versus: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
var altitude_ft = getprop("/position/altitude-ft") or 0.00; | var altitude_ft = getprop("/position/altitude-ft") or 0.00; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 204: | Line 204: | ||
Nasal is a language that has no statements, it's all about EXPRESSIONS. So you can put things in pretty much arbitrary places. | 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=" | <syntaxhighlight lang="nasal"> | ||
var do_something = func return 0; | var do_something = func return 0; | ||
if (a==1) { | if (a==1) { | ||
| Line 216: | Line 216: | ||
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: | 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=" | <syntaxhighlight lang="nasal"> | ||
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"); | ||
| Line 225: | Line 225: | ||
You can easily reduce the complexity of huge conditional (IF) statements, such as this one: | You can easily reduce the complexity of huge conditional (IF) statements, such as this one: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
if (a==1) function_a(); | if (a==1) function_a(); | ||
else | else | ||
| Line 239: | Line 239: | ||
.. just by using the variable as a key (index) into a hash, so that you can directly call the corresponding function: | .. just by using the variable as a key (index) into a hash, so that you can directly call the corresponding function: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
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] (); | ||
| Line 250: | Line 250: | ||
Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider this extract from weather_tile_management.nas: | Using this technique, you can reduce the complexity of huge conditional blocks. For example, consider this extract from weather_tile_management.nas: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal" line start="460"> | ||
if (code == "altocumulus_sky"){weather_tiles.set_altocumulus_tile();} | if (code == "altocumulus_sky"){weather_tiles.set_altocumulus_tile();} | ||
else if (code == "broken_layers") {weather_tiles.set_broken_layers_tile();} | else if (code == "broken_layers") {weather_tiles.set_broken_layers_tile();} | ||
| Line 273: | Line 273: | ||
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: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
weather_tiles["set_"~code~"_tile"](); # naming convention | weather_tiles["set_"~code~"_tile"](); # naming convention | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 285: | Line 285: | ||
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=" | <syntaxhighlight lang="nasal"> | ||
hash[key] (arguments...); | hash[key] (arguments...); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
| Line 291: | Line 291: | ||
For example, consider: | For example, consider: | ||
<syntaxhighlight lang=" | <syntaxhighlight lang="nasal"> | ||
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'; | ||