Yonaba / Lua-Class-System

Lua Class System (LCS) is a small library which offers a clean, minimalistic but powerful API for (Pseudo) Object Oriented programming style using Lua.
http://yonaba.github.com/Lua-Class-System
64 stars 17 forks source link

Default Cass attributes unexpected behavior with empty tables. #5

Closed awilliamson closed 11 years ago

awilliamson commented 11 years ago

I've found that if you set a default attrib as an empty table, eg children = {}. That upon editing that table, it will actually edit on the Class itself and never upon the instance like other attributes do. This has caused a few issues in my code and is very hard to track down.

I can't give you example code, but try making 2 instances of a Class which use the Class getter for a attribute which is defaulted to an empty table. If you let the class system assume the default and do no assignment in the init, it leads to unexpected behaviour.

EDIT: I decided to run a test case to show how the table reference is the exact same.

LCS = require 'LCS'

local Cls = LCS.class({
    x = 0,
    y = 0,
    visible = true,
    children = {}
})

function Cls:init(x,y,vis)
    self:setX(x)
    self:setY(y)
end

function Cls:getX()
    return self.x
end

function Cls:setX( x )
    self.x = x
end

function Cls:getY()
    return self.y
end

function Cls:setY( y )
    self.y = y
end

function Cls:isVisible()
    return self.visible
end

function Cls:setVisible( v )
    self.visible = v    
end

function Cls:getChildren()
    return self.children    
end

function Cls:addChildren(v)
    table.insert( self:getChildren(), v)    
end

local testObj1 = Cls(10,20)
local testObj2 = Cls(45,26)

testObj1:setVisible(false)

print("1:x:",testObj1:getX())
print("1:y:",testObj1:getY())
print("1:vis:",testObj1:isVisible())
print("1:children:",testObj1:getChildren())

print("2:x:",testObj2:getX())
print("2:y:",testObj2:getY())
print("2:vis:",testObj2:isVisible())
print("2:children:",testObj2:getChildren())

If you run that example code it should show the table references to be the same: Example Output

The style of code in the example is of rough design to that of my project, however I am doing this with an extended class, but this is clearly a system-wide issue.

I hope this is a bug that is not too difficult for you to fix, my temporary solution is to remove the usual default attrib definition from the class def and just plain self. attrib = {} inside the unit.

Use the snippet below to modify the original test case, and it should work.

local Cls = LCS.class({
    x = 0,
    y = 0,
    visible = true
})

function Cls:init(x,y,vis)
    self:setX(x)
    self:setY(y)

    self.children = {}
end

As you can see by the image below, this appears to fix the issue. Temp Fix

Yonaba commented 11 years ago

How is the above patch working for you ?

awilliamson commented 11 years ago

Yup seems to do it. I thought it would have just been a copy mistake somewhere, but it was very late my time. Thanks for the fix. Any news on the class extension fix?

Yonaba commented 11 years ago

Fine. I am closing this issue now. As for the class extension, I'll be working on it very soon.