lua-users home
lua-l archive

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




----------------------------------------
> Date: Tue, 22 Dec 2009 21:22:01 +0300
> Subject: Re: Deep __newindex on assignment?
> From: agladysh@gmail.com
> To: lua@bazar2.conectiva.com.br
>
>> I have a userdata which uses __index to return another userdata and __newindex to set the same data. The first userdata is basically a property bag and the second userdata represents a specific property type. For example, a property like 'Position' might represent a point in 3d space and provide x,y,z members and point math functions.
>
>> I wanted to set just one sub-member of a property in the bag, so I used the following syntax:
>
>> propBag.Position.z = 10
>
>> I was hoping this would result in a __newindex call for "Position" since this is effectively assigning a value to that index. Instead this performs a __index call for "Position" and then sets the "z" member on the resulting userdata, but the result is then simply lost because all I have modified is the Point on the stack and not the Point in the propBag.
>
>> Now obviously I can work around this problem by changing my script, but this syntax seems logical so I suspect it will be a common error for my end users (who will be authoring scripts that use these userdata objects). My question is can I make the syntax above work as I expected and result in a __newindex call on my propBag?
>
> You have to return a temporary proxy object from the __index handler.
> Set __newindex in that proxy object's metatable and handle assignment
> there.
>
> See for example how Lua Alchemy AS3 object property access wrapping is done:
>
> http://github.com/lua-alchemy/lua-alchemy/blob/master/alchemy/lua-lib/assets/lua_alchemy/as3/sugar.lua
>
> Alexander.

 
I had considered using a proxy, but won't that make it impossible to ever get a simple copy of the value? If I understand the sample code you linked that proxy would result in the following code modifying the original property bag:
 
  local pos = propBag.Position  -- pos is now the proxy object wrapping the Point userdata
  pos.z = 10                    -- this will use the proxy's __newindex thus setting the value in propBag
  otherBag.Position = pos
  assert(propBag.Position ~= otherBag.Position) -- this would fail as both were modified
 
With the above syntax I wouldn't want the original propBag to be modified. It seems like I would need some way of knowing if __index is being called due to a term on the left side of an assignment operator. Then I could use the proxy wrapper only in cases of eventual assignment, otherwise I could return an unwrappered value which effectively acts as a copy. Is that possible?
 
-Todd