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:
> To:
>> 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:
> 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?