About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

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

About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

xinlei fan
hi

I am a freshman in lua programming,and I worked with Javascript for several years

when I write a simple game framework using lua , I read the article on on 

http://www.lua.org/pil/16.1.html,the thoughts much like the prototype,but I noticed a code fragment

    function Account:new (o)
      o = o or {}   -- create object if user does not provide one
      setmetatable(o, self)
      self.__index = self
      return o
    end

I think "self.__index = self" is not make sense,it will lead to a "prototype circle",
because when you call Account:new({}) after, the table Account will have a 
prototype point to himself,and if you dump Account (loop each key in it,if is a table,loo
p the table and so on,in recursive),you will get an stack overflow error..... And in logic
when you create a "instance" of a "Class",you shouldn't change the "Class's" property or behavior 
I think it should code like this

    function Account:new (o)
      o = o or {}   -- create object if user does not provide one
      setmetatable(o, {__index = self})
      return o
    end

It's much easy to understand,and when you create instance of Account,you will not change the 

Account's any definition,and the table o(instance) also have a prototype point to Account(Class),it can call the method of the Account(Class)。

And I wrote a lua version simple-inheritance like JR's javascript version 


best regards!
Reply | Threaded
Open this post in threaded view
|

Re: About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

Pierre-Yves Gérardy
On Tue, Apr 23, 2013 at 4:53 PM, xinlei fan <[hidden email]> wrote:

>     function Account:new (o)
>       o = o or {}   -- create object if user does not provide one
>       setmetatable(o, self)
>       self.__index = self
>       return o
>     end
>
>
> I think "self.__index = self" is not make sense,it will lead to a "prototype
> circle",
>
> because when you call Account:new({}) after, the table Account will have a
> prototype point to himself [...]

No, that code doesn't create a cycle unless you call

    Account:new(Account)

Because it would set Account as its own prototype. Here's the minimal code
to create a prototype loop:

    t={}
    t.__index = t
    setmetatable(t,t)

In the PiL example, self becomes the metatable of the new object, not its own.

-- Pierre-Yves

Reply | Threaded
Open this post in threaded view
|

Re: About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

xinlei fan
But It's no need to "set Account as its own prototype", and actually there is a circle when you call Account:new(some table),because the sytax sugar colon,the Account is bind to the first hide parameter of the new  unction,in the new function,"self" point to the reciever of current method, it's Account.......

t={}
t.__index = t
setmetatable(t,t)

and I can't understand why we should set the some table's prototype to it's self



2013/4/23 Pierre-Yves Gérardy <[hidden email]>
On Tue, Apr 23, 2013 at 4:53 PM, xinlei fan <[hidden email]> wrote:
>     function Account:new (o)
>       o = o or {}   -- create object if user does not provide one
>       setmetatable(o, self)
>       self.__index = self
>       return o
>     end
>
>
> I think "self.__index = self" is not make sense,it will lead to a "prototype
> circle",
>
> because when you call Account:new({}) after, the table Account will have a
> prototype point to himself [...]

No, that code doesn't create a cycle unless you call

    Account:new(Account)

Because it would set Account as its own prototype. Here's the minimal code
to create a prototype loop:

    t={}
    t.__index = t
    setmetatable(t,t)

In the PiL example, self becomes the metatable of the new object, not its own.

-- Pierre-Yves


Reply | Threaded
Open this post in threaded view
|

Re: About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

Philipp Janda
In reply to this post by xinlei fan
Am 23.04.2013 16:53 schröbte xinlei fan:
> hi

Hi!

>
> I am a freshman in lua programming,and I worked with Javascript for several
> years
>
> when I write a simple game framework using lua , I read the article on on
>
> http://www.lua.org/pil/16.1.html,the thoughts much like the prototype,but I
> noticed a code fragment
>
>      function Account:new (o)
>        o = o or {}   -- create object if user does not provide one
>        setmetatable(o, self)
>        self.__index = self
>        return o
>      end
>
>
> I think "self.__index = self" is not make sense,it will lead to a
> "prototype circle",

This is a common hack to save some memory. I'm quite surprised that this
issue doesn't come up more often, so I will try to give a detailed
explanation:

Logically there are three tables involved: The object table (`ot` from
now on), the metatable (`mt`) and the index table (`it`).

Let's assume those tables have the following contents (in pseudo-Lua):
     ot = {}
     mt = {
       __index = ..., --> `it`
     }
     it = {
       field1 = 1,
     }
and `ot` has `mt` as its metatable.

If one accesses `ot.field1`, Lua checks whether `ot` has a field named
`field1`. It doesn't, so Lua checks whether `ot` has a metatable. It
does, so Lua loads this metatable `mt` and checks for an `__index`
field. There is an `__index` field in `mt` which points to `it`, so Lua
accesses the field `field1` in `it` and returns its value.
As all useful fields in a metatable start with two underscores, and the
fields in a common index table do *not* start with underscores, one can
actually merge `mt` and `it` into one table without conflict (let's call
it hack table `ht`).

     ot = {}
     ht = {
       __index = ..., --> `ht`
       field1 = 1,
     }
`ot` now has `ht` as its metatable.

If one now accesses `ot.field1`, Lua checks that there is no `field1` in
`ot` and loads the metatable `ht`. It checks for the `__index` field in
`ht` which points to `ht` again, so it now looks for `field1` in `ht`
and returns its value. We still have the same number of table fields,
but we saved the memory overhead of an empty table.

>
> because when you call Account:new({}) after, the table Account will have a

With `Account:new({})`:
*   `ot` is `o`, which is a new table `{}`
*   `ht` is `self`, which is the same as `Account`, which is the same as
`ht.__index` or `self.__index`

>
> [...]
>
> I think it should code like this
>
>      function Account:new (o)
>        o = o or {}   -- create object if user does not provide one
>        setmetatable(o, {__index = self})
>        return o
>      end

Yes, in that case
*   `ot` is `o`
*   `mt` is `{__index = self}`
*   `it` is `self` (which often will be the same as `Account`)

So this corresponds to the non-hack (three table) version.


HTH,
Philipp




Reply | Threaded
Open this post in threaded view
|

Re: About the example in "Object-Oriented Programming" on http://www.lua.org/pil/16.1.html

Karol Dro
Hi!

Great explanation!!!

--
Karol Drożak