The commented code with the if statement does work correctly. However, the ternary does not? Why is this or how can I implement this in one simple line?
local function dontwork()
local args = ""
local cmd_tb = {}
cmd_tb.args = ""
-- dont work
args = (#cmd_tb.args == 0 and false or cmd_tb.args)
-- dont work
-- args = (cmd_tb.args == "" and false or cmd_tb.args)
-- works correctly - empty
-- if #cmd_tb.args == 0 then
-- args = false
-- else
-- args = cmd_tb.args
-- end
if args then
print("yes:",args)
else
print("empty")
end
end
-- outputs 'yes'
dontwork()
This is a common pitfall.
cond and a or b
is not a ternary. It's just (cond and a) or b
, which, due to lazy evaluation, behaves almost like a ternary:
cond
is truthy, cond and a
evaluates to a
. If a
is truthy, a or b
then evaluates to a
.cond
is falsey, cond and a
evaluates to cond
, so cond or b
evaluates to b
.The problem is that if a
is falsey (nil
or false
), then a or b
evaluates to b
, when it should evaluate to a
.
In your case, since b
is truthy (nil
and false
don't support #
, unless you mess with debug metatables), you could just negate your condition and swap a
and b
:
args = #cmd_tb.args ~= 0 and cmd_tb.args or false
The or false
is not necessary in this case, since #cmd_tb.args ~= 0
will already evaluate to false
. It may be necessary if your condition could be nil
; or nil
is also sometimes useful when you want nil
rather than a boolean, but your condition produces a boolean.
PS: I would test for the empty string using ~= ""
/ == ""
respectively. It is clearer than comparing #x
against 0
.