Additions to packing and unpacking arguments

Pack function

To complement the “unpack” function, this section proposes to backport the “pack” function from Lua 5.2. This can be added either as the global function pack, or the library function table.pack (if the latter, it would be good to include table.unpack as an alias to unpack).

Definition of the pack function according to the Lua 5.2 manual:

table.pack (···)

Returns a new table with all parameters stored into keys 1, 2, etc. and with a field “n” with the total number of parameters. Note that the resulting table may not be a sequence.

Note that pack can be trivially implemented as the following:

function pack(...)
    return {n = select("#", ...), ...}
end

This change may have backwards incompatibilities with:

  • scripts that assume the pack global variable is nil

Agreement with this proposal

  • Agree
  • Neutral
  • Disagree

0 voters

Support field n in unpack

The “unpack” function has optional arguments i and j to specify the range of arguments to unpack. i is the lower bound, and j is the upper bound. When j is unspecified, it defaults to the length of the table as defined by the # operator.

local args = {1, 2, 3, nil, nil}
print(unpack(args, 2, 5)) --> 2, 3, nil, nil
print(unpack(args, 2))    --> 2, 3
print(unpack(args))       --> 1, 2, 3

This section proposes to change the behavior of unpack to include looking for field n in the table when determining the upper bound. This is to complement the pack function, which sets field n to indicate the number of packed arguments.

To get the upper bound:

  • If argument j is specified, then use it as the upper bound.
  • Otherwise, if field n of the table is a number, then use it as the upper bound.
  • Otherwise, use the length of the table as defined by the # operator.

This change may have backwards incompatibilities with:

  • scripts that call unpack on a table with field n, which expect the length of the table for the number of arguments. e.g.
    t = {1, 2, 3, n = 5}
    print(unpack(t))
    -- expect: 1, 2, 3
    -- result: 1, 2, 3, nil, nil
    

Note that this change is not present in later versions of Lua, though a similar proposal has been made.

Agreement with this proposal

  • Agree
  • Neutral
  • Disagree

0 voters

4 Likes

I’ve used this (implemented in Lua) quite a lot, especially when doing stuff with proxy functions, sandboxes, … and it seems like a good addition.

The change to unpack is a bit unnecessary though, but it does sound like it would make sense, regarding to table.pack being the inverse and adding the n field. I can’t think of any (pratical) example where this would backwards incompatible, but still it doesn’t feel right. (Any code where unpack is called with a table containing an n field is very likely to be generated by a (Lua-wise) pack function. It’s very unlikely that someone would use a pack function, which generates that n field, to not use it in unpack as an upper bound, but I guess it’s possible)

I feel like I’m mostly against the unpack change because it’s altering something in Lua (unlike porting something like utf8/table.pack or adding something new like math.clip), but I’m not sure whether that’s a bad thing or not.

I’m honestly for both as I find myself usually needing to make a table.pack implementation maybe here and there when trying to make silly things like interpreters, and unpack can be a bit annoying when I want say x to y where the start of the table I want ~= 1.

The only possible issue I see is the aesthetics of it with having table.pack but then unpack as a global function. Feels only right to have pack and unpack or table.pack and table.unpack.