Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua multiple assignment with tables

Tags:

lua

This code:

function foo()
    return 1, 2, 3
end

bar = {}

bar = {a, b, c = foo()}

produces:

bar.a = nil
bar.b = nil
bar.c = 1

How can this be written so that you get:

bar.a = 1
bar.b = 2
bar.c = 3

without having to write something like this:

function foo()
    return 1, 2, 3
end

bar = {}
a, b, c = foo()

bar = {a = a, b = b, c = c}
like image 541
Thorham Avatar asked Aug 03 '15 05:08

Thorham


1 Answers

BLUF

There's no straight forward or elegant way to do this. You'll have to do it manually like this

local r = { f() }           --> store all returned values in r
local bar = { }
local c = string.byte 'a'   --> start with 'a'
for _, v in ipairs(r) do
   local t = string.char(c)
   bar[t] = v               --> assign each value to respective letter
   c = c + 1
end

If you'd had a, b, c = foo() you'd get all the three values assigned to the three variables. However, you've

bar = { a, b, c = foo() }

This table constructor expression will get interpreted as the keys a, b, c getting inserted into the table, with only the last key having an associated value (aside: keys with no associated value are taken as nil; hence a and b never get inserted). Since there's only one variable to take the values returned by foo, except the first everything else it returns are discarded.

Alternatively bar = { foo() } will assign all values returned by foo as array values of bar. However, the key to access these would [1], [2], etc. and not 'a', 'b', etc.

Read below to know when the returned values get discarded and when they don't.


TL;DR All returned values are retained only when the function call is the last/only expression in a list of expressions; elsewhere all except the first are discarded.

Function call as a statement

In Lua, when we return multiple results from a function, all of them get discarded if the function call is a statement by itself.

foo()

will discard all three return values.

Function call in an expression

If it's used in an expression, only the first will be retained and everything else will be discarded.

x = foo() - 1
print(x)        -- prints 0; the values 2, 3 are discarded

Function call in an expression list

The entire list of values returned is retained only when the call appears as the last/only item in a list of expressions. Such list of expressions occur at four places in Lua:

  1. Multiple assignment

    E.g. local a, b, c, d = 0, f(). Here b, c, d get the values 1, 2, 3 respectively.

  2. Table constructor

    E.g. local t = { 0, f() }. All values returned by f are put into t following the first 0.

  3. Function call arguments

    E.g. g(a, f()). g would receive 4, not 2, arguments. a and the three values from f.

  4. return statement

    E.g. return 'a', f(). Additional to the string 'a', all values returned by f will be received at the calling end.

In all these situations, had f appeared not as the last expression in the list or wasn't the only expression, then all values it returned except the first would've been discarded.

Multiple assignment statement

In the multiple assignment statement, when the number of values assigned is lesser than number of variables, the extra variables be assigned to nil. When it's the other way around i.e if the number of variables are lesser, the extra values are discarded.

a, b, c = 1, 2         -- a = 1, b = 2, c = nil
a, b, c = 1, 2, 3, 4   -- 4 gets discarded
like image 147
legends2k Avatar answered Oct 05 '22 20:10

legends2k