lua-users home
lua-l archive

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

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, ... )
			-- do the regular processing possibly based on type( x )

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, ... )
			-- do the regular processing possibly based on type( x )

	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.


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.