Named Parameters

lua-users home
wiki

Lua supports named parameters by passing a table to a function. PiL Chap 5 describes this [1]. Therefore, the following function and call with positional arguments:

local function pipe(input, output)
  output:write(input:read'*a')
end
pipe(io.stdin, io.stdout)

may be written in a named parameter style as

local function pipe(t)
  local input  = assert(t.input)
  local output = assert(t.output)
  output:write(input:read'*a')
end
pipe({input=io.stdin, output=io.stdout})
pipe{input=io.stdin, output=io.stdout}  -- the following shorter syntax is equivalent and preferrred

Optionally, some type of argument checking is performed, which in the most rudimentary form involves the assert's above must could get more complicated like StructuralPatternMatching. It may be possible for a function to support both named and positional calling conventions:

local function pipe(...)
  local input, output
  if type(...) == 'table' then
    local t = ...
    input, output = assert(t.input or t[1]), assert(t.output or t[2])
  else
    input, output = ...
  end
  output:write(input:read'*a')
end
pipe(io.stdin, io.stdout)               -- positional form
pipe{input=io.stdin, output=io.stdout}  -- named form
pipe{io.stdin, output=io.stdout}        -- mixed form (positional and named)
pipe{io.stdin, io.stdout}               -- mixed form (using only positional)

Optional/default parameters can also be supported via

input, output = assert(t.input or t[1] or io.stdin), assert(t.output or t[2] or io.stdout)

To avoid ambiguity, the above assumes, however, that the first positional parameter can never be a table, or at least that if it is a table then it can be distinguished from a table of named parameters.

The programmer must remember to change the parenthesis from '()' to '{}' when using the named or mixed parameter forms.

One disadvantage of the named form is that the table construction does have some amount of overhead due to the table allocation. Benchmarking can determine how significant this is in practice. In a tight computationally intensive loop, it might be an issue.

Error handling in the named form is also somewhat more complicated and the code more verbose/ugly, but the same issues occur if a positional parameter has a nested structure that must be checked.

The named form does not preserve trailing nil's because trailing nil's are ignored in table constructors. Therefore, the following calls are indistinguishable:

f{a,b,nil,d=d}
f{a,b,d=d}

Here's some other, less conventional, possible ways to do named parameters:

f(a, b, {c=c})
f('a',a, 'b',b, 'c',c)  -- note: Perl supports a syntactic sugar for this: `a=>$a` is `'a',$a`
f(params().a(a).b(b).c(c)) -- C++ chained method call style.
f('c,b,a', c,b,a)  -- note: parameter resolution can be memoized (see link below)
f'c=$(c),b=$(b),a=$(a)' -- variant of above with StringInterpolation [1] syntax sugar for f('c=$(c),b=$(b),a=$(a)',c,b,c)

See Also


RecentChanges · preferences
edit · history
Last edited March 13, 2012 4:17 am GMT (diff)