anon
anon

Reputation: 42697

programming in lua, objects

Sample code:

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

taken from "Object-Oriented Programming: Classes" http://www.lua.org/pil/16.1.html

What is the purpose of the self.__index = self line? And why is it executed every time an object is created?

Upvotes: 9

Views: 7681

Answers (6)

clarkttfu
clarkttfu

Reputation: 625

Note that setmetatable(o, self) only set Account as metatable of o (otherwise nil by default). That's the first step of a prototype binding but it's NOT enough make functions of Account searchable from o!

To make o search methods on Account, the metatable object (Account) have to include a __index event with the value pointing to itself, which contains prototype methods.

So it's has to be done in 2 steps:

  1. create a metatable value with __index event
  2. setmetatable to the target table.

As said in the original book, this is "a small optimization" -- you will usually need another mold table value created as metatable of o. But here in this case, the code re-used the Acccount table value, as both metatable and prototype object.

Upvotes: 0

Jay Poss
Jay Poss

Reputation: 21

Creating objects (which are simply Tables) is quite different with Lua. The basic idea is to create a regular table containing attributes(functions and values) that are common to all instances. This table, I'll call CAT for Common Attributes Table.

If you reference an attribute in a table and Lua can't find this attribute, there is a way to tell Lua where else to look for the attribute. We want Lua to look in the CAT for common attributes. Metatables answer that need. More on how that works later.

We also need methods in the CAT to be able to use instance values. Self answers that need. When you call a table function (method) this way: tableName:methodName(), Lua automatically places a reference to the table object as the first parameter. The name of this parameter is self. Even though the method is located in the CAT, self will refer to the particular calling object instance table.

Say we have a CAT called Car.

metaCar = { __index = Car }  
-- this table will be used as the metatable for all instances of Car  
-- Lua will look in Car for attributes it can't find in the instance

For example:

-- instance table is called mustang    
-- setmetatable(mustang, metaCar)

Here is a general purpose function that creates new instance objects and sets the metatable for it. If the CAT has a constructor function (init), it gets executed as well.

function newObj(metatable)  
..obj = {}      -- create new empty instance object  
..setmetatable(obj, metatable) –- connect the metatable to it  
..if obj.init then  -- if the CAT has an init method, execute it  
....obj:init()  
..end  
..return obj  
end

Upvotes: 0

Judge Maygarden
Judge Maygarden

Reputation: 27613

Lua is not an object-oriented language, but it has all of the facilities for writing object-oriented code. However, it is done in a prototyping fashion a la JavaScript. Instead of explicitly creating classes, a prototype object is created and then cloned to create new instances.

The __index metamethod is invoked to perform key lookups on read accesses to a table when the key is not already present in the table. So, self.__index = self essentially allows for inheritance of all methods and fields of the Account "class" by the new "instance" that is created in the o = o or {} and setmetatable(o, self) lines.

See also:

Upvotes: 4

Liam
Liam

Reputation: 79

The Lua documentation is somewhat vague on this detail and many of the answers here either echo the Lua docs or don't thoroughly explain this confusing tidbit.

The line self._index = self is present purely for the benefit of the newly-created object, o; it has no meaningful or functional impact on Account.

The _index field only has special meaning within the context of metatables; therefore self._index is just a plain old regular field for Account. However, when Account is used as a metatable for o, the _index field "becomes" a metamethod for o. (So what's a field for Account is a metamethod for o.)

When you take the two statements in combination ...

(1)    setmetatable(o, self)
(2)    self._index = self

... you're using Account as the metatable for o on line (1) and setting the _index metamethod for o to Account on line (2). (On line (2), you're also setting the "plain old field" __index in Account to Account.) So the useful aspect of self._index = self isn't the setting of the _index field for Account, but rather the setting of the _index metamethod for o.

The following is functionally equivalent:

    setmetatable(o, self)
    getmetatable(o)._index = self

Upvotes: 7

David Haley
David Haley

Reputation: 373

As others have said, self (the Account table) is used as a metatable assigned to the objects created using new. Simplifying slightly (more info available at the links provided) when a field is not found in 'o', it goes to the 'Account' table because o's metatable says to go to Account (this is what __index does).

It does not, however, need to be executed every time an object is created. You could just as easily stick this somewhere:

Account.__index = Account

and it would work as well.

The somewhat longer story is that if an object o has a metatable, and that metatable has the __index field set, then a failed field lookup on o will use __index to find the field (__index can be a table or function). If o has the field set, you do not go to its metatable's __index function to get the information. Again, though, I encourage you to read more at the links provided above.

Upvotes: 10

Puppy
Puppy

Reputation: 147018

They're used to re-direct table accesses (local y = table[key]) which are also used in method calls. In the above line, object o will have any attempts to access keys re-directed to the current object self, effortlessly inheriting all member functions. And possibly data variables too, depending on what exactly that __index is and how it works.

Upvotes: 0

Related Questions