[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: __tonumber metamethod (was Re: Exposure of nil to end-users)
- From: Mark Hamburg <mark@...>
- Date: Thu, 5 Feb 2009 09:32:17 -0800
This points to a general pattern of wanting to write functions that
interact with metatables roughly along the following lines:
function fn( x, ... )
local mtx = getmetatable( x )
local mtx_fn = mtx and mtx.__fn
if mtx_fn ~= nil then
return mtx_fn( x, ... )
else
-- do the regular processing possibly based on type( x )
end
end
Now, one alternative is to support this via methods so that instead of
calling fn( x ) we call x:fn(). This works to the extent that one can
add methods to the base types as well and perhaps that style should
simply be encouraged. (Certainly the everything is an object languages
would lean this way.)
But if we stick with functions rather than methods, then we have an
interesting problem here in that the pattern fights with metatable
security. The metatables for userdata are always protected from Lua
code and if you don't trust the Lua code you are calling, you may want
to protect the metatables of Lua-based objects as well using the
__metatable entry. Do we perhaps just say that one cannot protect the
methods in metatables from execution by defining for example:
callmetamethod( x, "__fn", ... )
Which would do much the same thing? It might need a protected form to
handle the case where the metamethod wasn't defined. Or we need a way
to test for the presence of the metamethod as well.
For further protection, we could actually insist that the key be
something non-forgeable -- i.e., not a string. Then the construct
might be:
local function fn_local( x, ... )
if hasmetamethod( x, fn_local ) then
return callmetamethod( x, fn_local, ... )
else
-- do the regular processing possibly based on type( x )
end
end
fn = fn_local
Here we use the function itself as the identifier. Only code that can
get to the function declaration can access the metatable entry.
I have to admit that I'm not thrilled with where this chain of
reasoning leads and the method-based approach starts to look more and
more attractive.
Mark
P.S. Along the way I got thinking about read-only metatables as an
option and then decided that what one really wants are tables where
you can't overwrite an existing key -- in some sense the opposite of
the __newindex metamethod. But that's a different discussion. I know
you can implement it using proxy tables and __index and __newindex. It
just isn't particularly pretty.