Define default values for function arguments
Solution 1
If you want named arguments and default values like PHP or Python, you can call your function with a table constructor:
myfunction{a,b=3,c=2}
(This is seen in many places in Lua, such as the advanced forms of LuaSocket's protocol modules and constructors in IUPLua.)
The function itself could have a signature like this:
function myfunction(t)
setmetatable(t,{__index={b=7, c=5}})
local a, b, c =
t[1] or t.a,
t[2] or t.b,
t[3] or t.c
-- function continues down here...
end
Any values missing from the table of parameters will be taken from the __index
table in its metatable (see the documentation on metatables).
Of course, more advanced parameter styles are possible using table constructors and functions- you can write whatever you need. For example, here is a function that constructs a function that takes named-or-positional argument tables from a table defining the parameter names and default values and a function taking a regular argument list.
As a non-language-level feature, such calls can be changed to provide new behaviors and semantics:
- Variables could be made to accept more than one name
- Positional variables and keyword variables can be interspersed - and defining both can give precedence to either (or cause an error)
- Keyword-only positionless variables can be made, as well as nameless position-only ones
- The fairly-verbose table construction could be done by parsing a string
- The argument list could be used verbatim if the function is called with something other than 1 table
Some useful functions for writing argument translators are unpack
(moving to table.unpack
in 5.2), setfenv
(deprecated in 5.2 with the new _ENV
construction), and select
(which returns a single value from a given argument list, or the length of the list with '#'
).
Solution 2
In my opinion there isn't another way. That's just the Lua mentality: no frills, and except for some syntactic sugar, no redundant ways of doing simple things.
Solution 3
Technically, there's b = b == nil and 7 or b
(which should be used in the case where false
is a valid value as false or 7
evaluates to 7), but that's probably not what you're looking for.
Solution 4
The only way i've found so far that makes any sense is to do something like this:
function new(params)
params = params or {}
options = {
name = "Object name"
}
for k,v in pairs(params) do options[k] = v end
some_var = options.name
end
new({ name = "test" })
new()
Solution 5
If your function expects neither Boolean false
nor nil
to be passed as parameter values, your suggested approach is fine:
function test1(param)
local default = 10
param = param or default
return param
end
--[[
test1(): [10]
test1(nil): [10]
test1(true): [true]
test1(false): [10]
]]
If your function allows Boolean false
, but not nil
, to be passed as the parameter value, you can check for the presence of nil
, as suggested by Stuart P. Bentley, as long as the default value is not Boolean false
:
function test2(param)
local default = 10
param = (param == nil and default) or param
return param
end
--[[
test2(): [10]
test2(nil): [10]
test2(true): [true]
test2(false): [false]
]]
The above approach breaks when the default value is Boolean false
:
function test3(param)
local default = false
param = (param == nil and default) or param
return param
end
--[[
test3(): [nil]
test3(nil): [nil]
test3(true): [true]
test3(false): [false]
]]
Interestingly, reversing the order of the conditional checks does allow Boolean false
to be the default value, and is nominally more performant:
function test4(param)
local default = false
param = param or (param == nil and default)
return param
end
--[[
test4(): [false]
test4(nil): [false]
test4(true): [true]
test4(false): [false]
]]
This approach works for reasons that seem counter-intuitive until further examination, upon which they are discovered to be kind of clever.
If you want default parameters for functions that do allow nil
values to be passed, you'll need to do something even uglier, like using variadic parameters:
function test5(...)
local argN = select('#', ...)
local default = false
local param = default
if argN > 0 then
local args = {...}
param = args[1]
end
return param
end
--[[
test5(): [false]
test5(nil): [nil]
test5(true): [true]
test5(false): [false]
]]
Of course, variadic parameters completely thwart auto-completion and linting of function parameters in functions that use them.
ripat
Airline pilot by day and night. Linux enthusiast the rest of the time. "Why is it that all of the instruments seeking intelligent life in the universe are pointed away from Earth?"
Updated on May 01, 2021Comments
-
ripat about 3 years
In the Lua wiki I found a way to define default values for missing arguments:
function myfunction(a,b,c) b = b or 7 c = c or 5 print (a,b,c) end
Is that the only way? The PHP style
myfunction (a,b=7,c=5)
does not seem to work. Not that the Lua way doesn't work, I am just wondering if this is the only way to do it.