[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Static typing in Lua
- From: Tomas <tomas@...>
- Date: Thu, 27 Jul 2006 17:16:02 -0300 (BRT)
Hi Alexander
In my opinion, to the purpose of (runtime) type checking, "validator"
should recognize following "type kinds":
nil
any
optional_any
T
optional_T
where T is a "conventional" Lua type (number, table, userdata etc.),
and optional_T is either conventional Lua type or nil (like
optional_table); any is any type except nil, and optional_any is any
type or nil.
I think "optional_any" means "nothing to do", as the value could
be of any type and even absent!
Having nil as equivalent to any type is dangerous here.
Until we began to widely use type-validating assertions, and installed
global table protection, large percent of our bugs were due to
nil-generating behaviour shown above.
We developed a small set of functions that mimics some of the
luaL_check* and luaL_opt*. It is not a complete set, we just make the
functions we needed. The use of the debug library to provide better
error messages is not always efectively. Also, its use cause a great
performance hit, so we decided to remove all occurrences of `check' from
the production code (we also developed a small script to do the job).
This is one of the reasons for omitting the default values.
The following line is a simple example of its use (obviously,
after `require"check"'):
function select (tabname, fields, cond, extra)
check.str (tabname, 1, "sql.select")
check.str (fields, 2, "sql.select")
check.optstr (cond, 3, "sql.select")
check.optstr (extra, 4, "sql.select")
...
end
The second and third arguments to the functions are just to
improve the error message.
The library code follows.
Tomas
----------------------------------------------------------
local error, type = error, type
local debug = debug
local string = require"string"
module"check"
local errmsg = "bad argument #%d to `%s' (%s expected, got %s)"
local function build_assert (expected)
return function (v, n, f)
if not f then
f = debug.getinfo (2, "n").name
end
local t = type (v)
if t ~= expected then
error (string.format (errmsg, n, f, expected, t), 3)
end
end
end
local function build_optassert (func)
return function (v, n, f)
if not v then return end
if not f then
f = debug.getinfo (4, "n").name
end
_M[func] (v, n, f)
end
end
function str (v, n, f)
if not f then
f = debug.getinfo (2, "n").name
end
local t = type (v)
if t ~= "string" and t ~= "number" then
error (string.format (errmsg, n, f, "string", t), 3)
end
end
optstr = build_optassert ("str")
table = build_assert ("table")
opttable = build_optassert ("table")
udata = build_assert ("userdata")