Why does table.unpack() behave like this in logic conditions?

table.unpack(t) where t is a table is a function that can be used to convert a table to a tuple, for anyone not aware tuples are a list of arguments that aren’t grouped, unlike tables. So a, b is a tuple and {a, b} is a table.

Also in logic conditions the equivalent of a ternary operator(x = condition ? a : b where if condition evaluates to true x becomes a else b) can be written in the following way:

local x = condition and a or b

So whats the issue? Well when I return table.unpack(t) as it is all the values are returned, but when I return condition and table.unpack(t) or nil only the first table.unpack(t) value is returned if the condition is true. So I’m simply asking, why not all the values in this case?

1 Like

That’s because in lua tuples are not data like a number, a string or a function. You cannot store a tuple in a variable or pass a tuple as an argument (rather all arguments are a tuple). In other words a tuple is not a first class citizen.

By default in lua, when a function returns multiple values, such as table.unpack(), only the first one is taken into account. Except in places where multiple values are accepted such as in assignment or function arguments.

Refer to @lumizk’s answer for the answer to your question. This is just here to clarify the use of Lua ternary operators.

Lua ternary operators are different from ternary operators in other languages. In your JavaScript example of a ternary operator, the code literally translates to:

let x;
if (condition) {
    x = a;
} else {
    x = b;
}

However, Lua ternary operators do not behave like this. They are instead an “abuse” (for lack of a better term) of the truthiness of variables. This would be the equivalent behavior of a Lua ternary:

local x
if condition and a then
    x = a
else
    x = b
end

The important difference is that, in Lua, both condition and a must be truthy for x = a. For the most part, this is a distinction that can be ignored, but if you ever need to differentiate between false and nil, then you might run into some problems.

This is covered in the manual:

Both function calls and vararg expressions can result in multiple values. If an expression is used as a statement (only possible for function calls (see §2.4.6)), then its return list is adjusted to zero elements, thus discarding all returned values. If an expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the call is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, discarding all values except the first one.

Any expression enclosed in parentheses always results in only one value. Thus, (f(x,y,z)) is always a single value, even if f returns several values. (The value of (f(x,y,z)) is the first value returned by f or nil if f does not return any values.)
- Lua 5.1 Reference Manual, ch 2 sec 5.

It has lots of examples at the page I linked to. I believe your specific case falls into this rule:

In all other contexts, Lua adjusts the result list to one element, discarding all values except the first one.

2 Likes