[Loop-users] Using the Scoped Model with Table-Access Metamethods

Renato Maia maia at inf.puc-rio.br
Thu May 14 12:33:19 GMT+2 2009


Hi.

On 14 May 2009, at 00:25, Kurt Nordstrom wrote:
> To take security a step further, I'd like to implement custom  
> versions of both the __index and the __newindex metamethods on game  
> objects to limit who could see and change certain fields.  However,  
> my understanding is that LOOP uses these metamethods to handle  
> inheritance and member access.

OK, but one thing you should know about these metamethods is that they  
are not ideal to implement access control for tables (this is one of  
the main reasons why is not easy to implement privacy objects in Lua).  
The reason is that these metamethods are only called when you try to  
index a missing key, for example:

local object = { secret = "Top Secret Stuff" }
setmetatable(object, { __index = function() error "access denied" end })
print(object.secret) --> "Top Secret Stuff"
print(object.missing) --> raises error "access denied"

Therefore, you won't be able to deny access to values already defined  
in the object. However, there are some techniques to avoid this  
limitation (for example, see http://www.lua.org/pil/16.4.html).

> So...my question is...is there a way to implement custom table- 
> access meta-methods on top of the LOOP scoped model without breaking  
> things?


For most LOOP models, the answer is no, since you'd have to implement  
the inheritance yourself in these metamethods. However, coincidently,  
with 'loop.scoped' you can define customized '__index' and  
'__newindex' metamethods, which will be invoked when a field is not  
found neither in the object itself, nor its class and superclasses,  
without breaking the inheritance mechanism. You can even define  
different metamethods for each scope. Just like 'loop.cached', these  
metamethods are inherited across the class hierarchy. For example:

local function showIndexAttempt(scope)
	return function(self, key)
		io.write("--> attempt to index ",scope," field ",key,"\n")
	end
end

local Base = oo.class{
	private   = { prvAtt = "private attrbiute",
		            __index = showIndexAttempt("private")	},
	protected = { prtAtt = "protected attribute",
		            __index = showIndexAttempt("protected") },
	public    = { pubAtt = "public attribute",
		            __index = showIndexAttempt("public") },
}
function Base.public:showAtt(name)
	io.write("  ",name," = ",tostring(self[name]),"\n")
end

local Class = oo.class({ clsAtt = "class attribute" }, Base)

local obj = Class{ objAtt = "object attribute" }
obj:showAtt("prvAtt")
obj:showAtt("prtAtt")
obj:showAtt("pubAtt")
obj:showAtt("clsAtt")
obj:showAtt("objAtt")
obj:showAtt("missing")

The drawback of this feature is that you cannot use '__index' and  
'__newindex' to override the way 'loop.scoped' implement the access to  
the object, as you can in other LOOP models. This is similar to the  
limitation I mentioned earlier about these metamethods in plain Lua.

Finally, be warned that 'loop.scoped' is by far the most complicated  
and less tested LOOP implementation. I'm interested in improving it  
though. So any feedback is very welcome. ;-)

Best regards.


--
Renato Maia
PhD student at PUC-Rio
__________________________
http://www.inf.puc-rio.br/~maia/




More information about the Loop-users mailing list