Problem with OOP in lua

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem with OOP in lua

bean
Hi!

    I'm using Lua.5.1, I have been trying to emulate class in Lua. I have been reading the chapter 16 in the PIL.
it does well, but it has a flaw:
    Account = {balance = 0}

    function Account:deposit(v)
        self.balance = self.balance + v
    end
    function Account:new(o)
         o = o or {}
         setmetatable(o, self)
         self.__index = self
         return o    
    end
    a = Account:new()
    b = Account:new()
   
    a:deposit(2)
    print("a=", a.balance)
    print("b=", b.balance)
output:
    a=2
    b=0

but there is a problem. if the balance is not a number, it's a table, as follows:
      Account = {balance = {0}}

    function Account:deposit(v)
        self.balance[1] = self.balance[1] + v
    end
    function Account:new(o)
         o = o or {}
         setmetatable(o, self)
         self.__index = self
         return o    
    end
    a = Account:new()
    b = Account:new()
   
    a:deposit(2)
    print("a=", a.balance)
    print("b=", b.balance)

output:
    a = {2}
    b = {2}
The instance a is changed and the instance b is changed too. This may be a flaw, how to improve it!

Thanks you!

----
bean
Reply | Threaded
Open this post in threaded view
|

Re: Problem with OOP in lua

陈果
In my opinion, this is not lua's flaw. balance is a class variable like in c++. Instances of Account don't have a field named balance.Then when you write a.balance=xxx, it will set the value to the metatable of a, which is Account.
So the correct way is to set property to instance not to metatable when you create the instance.Like following:
Account={
    new = function(self, balance)
        o={}
        o.balance=balance
        setmetatable(o,self)
        self.__index=self
        return o
    end
}

 
在06-4-13,许斌 <[hidden email]> 写道:
Hi!

   I'm using Lua.5.1, I have been trying to emulate class in Lua. I have been reading the chapter 16 in the PIL.
it does well, but it has a flaw:
   Account = {balance = 0}

   function Account:deposit(v)
       self.balance = self.balance + v
   end
   function Account:new(o)
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        return o
   end
   a = Account:new()
   b = Account:new()

   a:deposit(2)
   print("a=", a.balance)
   print("b=", b.balance)
output:
   a=2
   b=0

but there is a problem. if the balance is not a number, it's a table, as follows:
     Account = {balance = {0}}

   function Account:deposit(v)
       self.balance[1] = self.balance [1] + v
   end
   function Account:new(o)
        o = o or {}
        setmetatable(o, self)
        self.__index = self
        return o
   end
   a = Account:new()
   b = Account:new()

   a:deposit(2)
   print("a=", a.balance)
   print("b=", b.balance)

output:
   a = {2}
   b = {2}
The instance a is changed and the instance b is changed too. This may be a flaw, how to improve it!

Thanks you!

----
bean



--
Best Regards.

Chen guo
Tongji University, China
Reply | Threaded
Open this post in threaded view
|

Re: Problem with OOP in lua

Aaron Brown
In reply to this post by bean
bean wrote:

> but there is a problem. if the balance is not a number,
> it's a table,

If objects share tables, then they will reflect each others
changes.  This means that new() needs to create all tables
(two, in your problem case) needed by the new object.  For
example, you could change new's first line to:

    o = o or {balance = {0}}

--
Aaron
Reply | Threaded
Open this post in threaded view
|

Re: Problem with OOP in lua

Dolan, Ryanne Thomas (UMR-Student)
In reply to this post by bean
Remember that given:

a = {};

a is just a reference to the table constructed by {}.  This is evidenced
by the fact that you can alias the table:

b = a;
b.member = 1;
=a.member;

Since a and b reference the same table, changing one will change the
other.  I try to keep in mind this simple rule when dealing with Lua:
tables are only created when you see the table constructor {}.

So, your problem is analogous to a class in C++ which has pointer
members.  You must either manually initialize the pointers once you
instantiate a class, or else you can use a constructor.

In Lua the problem is not pointers but references to tables.  To fix the
problem you can either initialize the references manually or in your
constructor:

Example = {
    member1 = "hello world";
    member2 = {};
};

function Example:new (obj)
    obj = obj or {};
    obj.member2 = {};  --initialize member table references
...



On Thu, 2006-04-13 at 17:01 +0800, 许斌 wrote:

> Hi!
>
>     I'm using Lua.5.1, I have been trying to emulate class in Lua. I have been reading the chapter 16 in the PIL.
> it does well, but it has a flaw:
>     Account = {balance = 0}
>
>     function Account:deposit(v)
>         self.balance = self.balance + v
>     end
>     function Account:new(o)
>          o = o or {}
>          setmetatable(o, self)
>          self.__index = self
>          return o    
>     end
>     a = Account:new()
>     b = Account:new()
>    
>     a:deposit(2)
>     print("a=", a.balance)
>     print("b=", b.balance)
> output:
>     a=2
>     b=0
>
> but there is a problem. if the balance is not a number, it's a table, as follows:
>       Account = {balance = {0}}
>
>     function Account:deposit(v)
>         self.balance[1] = self.balance[1] + v
>     end
>     function Account:new(o)
>          o = o or {}
>          setmetatable(o, self)
>          self.__index = self
>          return o    
>     end
>     a = Account:new()
>     b = Account:new()
>    
>     a:deposit(2)
>     print("a=", a.balance)
>     print("b=", b.balance)
>
> output:
>     a = {2}
>     b = {2}
> The instance a is changed and the instance b is changed too. This may be a flaw, how to improve it!
>
> Thanks you!
>
> ----
> bean

Reply | Threaded
Open this post in threaded view
|

Re: Problem with OOP in lua

bean
Ryanne Thomas Dolan write:

>In Lua the problem is not pointers but references to tables.  To fix the
>problem you can either initialize the references manually or in your
>constructor:

>Example = {
>   member1 = "hello world";
>  member2 = {};
>};

>function Example:new (obj)
>   obj = obj or {};
>    obj.member2 = {};  --initialize member table references
>...
As a class, it is well, but if we want to make inheritance,  it has a problem.
function Example:new (obj)
   obj = obj or {};
    obj.member2 = {};  --initialize member table references
...
end

NewClass = Example:new()

function NewClass:new (obj)
   obj = obj or {};
    setmetatable(obj, self)
   ...
end

a = NewClass:new()
b = NewClass:new()

a.member2 and b.member2 still have the same reference. of course, we can do that
function NewClass:new (obj)
   obj = obj or {};
    obj.member2 = {};  --initialize member table references
    setmetatable(obj, self)
    ...
end
Then we must initialize member table references in all the inheritance class, But it make the code ugly! how to resolve it gracefully!


 bean