LuaVariadic Arguments


Introduction

Varargs, as they are commonly known, allow functions to take an arbitrary number of arguments without specification. All arguments given to such a function are packaged into a single structure known as the vararg list; which is written as ... in Lua. There are basic methods for extracting the number of given arguments and the value of those arguments using the select() function, but more advanced usage patterns can leverage the structure to it's full utility.

Syntax

  • ... -- Makes the function whose arguments list in which this appears a variadic function
  • select(what, ...) -- If 'what' is a number in range 1 to the number of elements in the vararg, returns the 'what'th element to the last element in the vararg. The return will be nil if the index is out of bounds. If 'what' is the string '#', returns the number of elements in the vararg.

Remarks

Efficiency

The vararg list is implemented as a linked list in the PUC-Rio implementation of the language, this means that indexes are O(n). That means that iterating over the elements in a vararg using select(), like the example below, is an O(n^2) operation.

for i = 1, select('#', ...) do
    print(select(i, ...))
end

If you plan on iterating over the elements in a vararg list, first pack the list into a table. Table accesses are O(1), so iterating is O(n) in total. Or, if you are so inclined, see the foldr() example from the advanced usage section; it uses recursion to iterate over a vararg list in O(n).

Sequence Length Definition

The vararg is useful in that the length of the vararg respects any explicitly passed (or computed) nils. For example.

function test(...)
    return select('#', ...)
end

test()             --> 0
test(nil, 1, nil)  --> 3

This behavior conflicts with the behavior of tables however, where the length operator # does not work with 'holes' (embedded nils) in sequences. Computing the length of a table with holes is undefined and cannot be relied on. So, depending upon the values in ..., taking the length of {...} may not result in the 'correct' answer. In Lua 5.2+ table.pack() was introduced to handle this deficiency (there is a function in the example that implements this function in pure Lua).

Idiomatic Use

Because varargs carry around their length people use them as sequences to avoid the issue with holes in tables. This was not their intended usage and one the reference implementation of Lua does not optimize for. Although such usage is explored in the examples, it is generally frowned upon.