lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


	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")