How to check function argument types?
Dynamic typing leads to simple, general code. The function
function sqr(x) return x*x end
will work with any value that can be multiplied, i.e. either a number or an object which has defined the __mul
metamethod. Also, since type()
returns the actual Lua type, we can do various things depending on what we have been passed. Needless to say, this flexibility comes at a price, especially in a large code base. Good function documentation becomes essential.
Of course, the compiler does not read the documentation. There are type checking approaches which embed type information into Lua code. One style is to use assert
on every function argument:
function sqr(x)
assert(type(x) == "number", "sqr expects a number")
return x*x end
We now get an explicit meaningful error, at the cost of a lot of typing and a potentially significant runtime cost, In Lua, assert()
is not a macro as it is in C, so it cannot be simply turned off. The typing can be reduced by defining suitable helper functions, but there are going to still be a lot of checks. Another objection is that the types of the function arguments are entirely contained in the function's implementation, and so cannot be accessed without some clever (and brittle) code analysis.
A promising approach is to use decorators:
sqr = typecheck("number","->","number") ..
function (x)
return x*x end
Now the signature of sqr
is explicit and up-front, easily extract-able from the source, and actual runtime type checking can be turned off or on.
The type constraint 'number' is too specific, but one could define and use predicates like is_number()
.
It is worth seriously considering Metalua, which is a smart, extensible Lua macro compiler (in the full Lisp sense of 'hygienic macro'). This syntax becomes possible:
-{ extension "types" }
function sum (x :: list(number)) :: number
local acc :: number = 0
for i=1, #x do acc=acc+x[i] end
return acc end