lua-users home
lua-l archive

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


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