Search code examples
luavariable-assignmentconditional-operatorlua-5.2

Why Lua's ternary operator is preventing my function to return several values?


As summary states. Lets say I want o resolve my ReturnFunction in a ternary operator fashion. Well, as far as I know, as long as my function returning several values (ReturnThreeValues) is placed at LAST position after ReturnFunction's return, the three values it gives should be returned by ReturnFunction if the ternary operator do what I think is the expected here, but for some reason it keeps returning ReturnOneValue's value even when n == nil (because I'm not including it when calling). It can be seen & tryed here:

<script src="//github.com/fengari-lua/fengari-web/releases/download/v0.1.4/fengari-web.js"></script>
<script type="application/lua">

    function ReturnOneValue(t, n)
        n = n or 1
        return t[n]
    end

    function ReturnThreeValues(t)
        return t[1], t[2], t[3]
    end

    function ReturnFunction(t, n)
        return n ~= nil and ReturnOneValue(t, n) or ReturnThreeValues(t)
    end

    local t = {"One", "Two", "Three"}
    local r1, r2, r3 = ReturnFunction(t)

    print(r1, r2, r3)

</script>

Well, basically I don't get why my print result is being: "One nil nil" and not: "One Two Three" as it should be, if the ternary operator was working as (I think is the) expected... Or is there something I'm not taking into account when it comes to resolve a multi-return function in this ternary way?

EDIT:

FTR (and just in case is useful for anyone), after doing some more research I got to find this other question with a possible workaround and turns out it works, as can be seen here:

<script src="//github.com/fengari-lua/fengari-web/releases/download/v0.1.4/fengari-web.js"></script>
<script type="application/lua">

    function ReturnOneValue(t, n)
        n = n or 1
        return t[n]
    end

    function ReturnThreeValues(t)
        return t[1], t[2], t[3]
    end

    function ReturnFunction(t, n)
        return n == nil and {ReturnThreeValues(t)} or {ReturnOneValue(t, n)}
    end

    local t = {"One", "Two", "Three"}
    local r1, r2, r3 = table.unpack(ReturnFunction(t))

    print(r1, r2, r3)

</script>

However, I'm not going to considerate it the right solution to the problem due to in the end it's more convoluted than what I was expecting to find, and I don't think the added complexity would worth after all... It's clear the way to go would be more in the line LMD suggests. Even though, after some consideration, I'm going to mark Nicol's answer as the right one, since he explained very well the why of such behavior and what was really happening under-the-hood, and that's what this question was actually more about. Well, thanks to everyone and I hope it makes sense.


Solution

  • Lua doesn't have a "ternary operator". What Lua has are and and or operators which only consider the values nil and false to be non-true. As such, X and Y resolves to X if X is non-true, and Y otherwise.

    However, expressions like and and or cannot handle multiple values. A function call can be used in certain places that can handle multiple variables (the initializer for a series of variables or a table, for example). But if a function call is used in other places (such as being the operand of an expression, like and and or), the return values are truncated down to a single value.

    What you're trying to do is not directly possible in Lua. It treats multiple values as a kind of special case circumstance, not one that can survive contact with most expressions.