I saw this being discussed in Corona Geek Episode 115 and thought I’d add my two cents..
The issue comes about when passing boolean values as optional arguments to a function, and how to efficiently test if nil and provide a default value. The common pattern for defaulting other types of values is:
1 2 3 4 5 |
function foo(anOptionalNumber) local theCleanedValue = anOptionalNumber or 1234 -- if anOptionalNumber is nil, the logical or will instead return 1234, as a "default" value -- etc end |
This is a shortcut test for nil, using the fact that nil evaluates to false in logical statements, so the expression after “or” is returned instead.
However, if you’re passing a boolean value, this test is insufficient, because a legitimately supplied “false” value will always fail that test (and thus always return the default instead).
1 2 3 4 5 |
function bar(anOptionalBoolean) local theCleanedValue = anOptionalBoolean or true -- if you pass nil you get default true, ok -- if you pass false you still get true, not ok end |
The “flaw” is in the binary logical test – as it’s essentially testing the wrong thing. It shouldn’t be testing for an implied false, it should be testing for an explicit nil. What would be handy is a ternary operator, to directly test for nil, then selecting either the passed value or the default. Some languages like C/C++ have a true ternary operator. Lua does not, though something nearly equivalent can be crafted from slightly more complex logical expressions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
function foo(anOptionalBoolean) local theDefaultValue = true -- this is ternary pattern when the default value is to be true: local theCleanedValue = (anOptionalBoolean==nil) and theDefaultValue or anOptionalBoolean print(theCleanedValue) end print("theDefaultValue=true, so expect: true, false, true") foo(nil) foo(false) foo(true) function bar(anOptionalBoolean) local theDefaultValue = false -- this is the ternary pattern when the default value is to be false: local theCleanedValue = (anOptionalBoolean~=nil) and anOptionalBoolean or theDefaultValue print(theCleanedValue) end print("theDefaultValue=false, so expect: false, false, true") bar(nil) bar(false) bar(true) |
The parenthesis surrounding the nil test are optional, but I added them to more closely imply the general form of the ternary pattern: a and b or c
But it’s not a “true” ternary operator, and there are some “gotchas”, particularly if “b” evaluates to false. That’s why foo() and bar() above are not identical – the logic must be reversed if your default value is intended to be false.
But with a bit of “practice” to keep the logic straight, defaulting booleans can again become a simple “one-liner”.
For further info, see the Lua Wiki entry on this topic.