Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is happening when I call unpack() as lua's function arguments?

Tags:

arguments

lua

Here is what I see:

> function test(...)
>>  for i, v in ipairs({...}) do
>>    print(v)
>>  end
>>end

-- This is expected
> test(unpack({1,2}))
1
2
-- When I mix unpack and regular arguments
-- What happened to 2?
> test(unpack({1,2}), 3)
1
3
-- What happened to 3?
> test(unpack({}), 3)

-- When I put regular args before unpack, everything is fine:
> test(1, unpack({2, 3}))
1
2
3

When I mix unpacked arguments with regular args, the result are weird. Could you explain what is happening under the hood?

like image 877
NeoWang Avatar asked Mar 13 '23 05:03

NeoWang


2 Answers

See explanation in Lua's manual:

If an expression is used as the last (or the only) element of a list of expressions, then no adjustment is made (unless the expression is enclosed in parentheses). In all other contexts, Lua adjusts the result list to one element, either discarding all values except the first one

You get exactly this. Unpack() returns multiple values, and list of returned elements gets adjusted down to 1 element, unless it is the last expression in test() arguments.

like image 78
Vlad Avatar answered Mar 29 '23 23:03

Vlad


I'll quote the Lua reference:

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.

As you see your unpack call is reduced to one return value as it is neither the last nor the only expression in the list of expressions you pass to test:

test(unpack({1,2}), 3)

In the other case the answer is quite simple:

test(unpack({}), 3)

The first value passed to test is nil. Therefor for i, v in ipairs({...}) do end will do nothing as your table's first value is nil as unpack({}) returns nil

ipairs (t)

Returns three values (an iterator function, the table t, and 0) so that the construction

 for i,v in ipairs(t) do body end

will iterate over the key–value pairs (1,t[1]), (2,t[2]), ..., up to the first nil value.

like image 37
Piglet Avatar answered Mar 30 '23 01:03

Piglet