4 Replies - 1542 Views - Last Post: 27 May 2016 - 04:35 AM Rate Topic: -----

#1 DouglasNewton  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 11-August 13

[Lua] OO - why the redundant assignment of __index?

Posted 04 December 2013 - 08:53 AM

I'm learning how to implement basic OO in Lua. I've found online from various sources that this is the common format for a (very) simple 'class' that can make instances of itself:
MyClass = {}
MyClass.__index = MyClass

function MyClass:new(o)
  local o = o or {}
  setmetatable(o,self)
  self.__index = self
  return o
end


The use of metatables and __index finally makes sense to me after studying the manual. In the past I used to (incorrectly) set the __index of 'o' to self, which would obviously not make much difference until inheritance comes into play, but from what I understand the latter makes more (as opposed to zero) sense than setting 'self.__index = self'.

The 'self' in this case refers to MyClass, right? Then it's the equivalent of saying 'MyClass.__index = MyClass'. But looky there - that's the exact line above the 'new' function.

My question is this: 1) Why does this line need to be there at all, since the equivalent is executed already?
and 2) Why does it need to be called every time a new object is created? - there could be many instances, but only one 'class'

Could anyone give insight to this apparent redundancy?

Thanks

Is This A Good Question/Topic? 0
  • +

Replies To: [Lua] OO - why the redundant assignment of __index?

#2 ishkabible  Icon User is offline

  • spelling expret
  • member icon





Reputation: 1737
  • View blog
  • Posts: 5,890
  • Joined: 03-August 09

Re: [Lua] OO - why the redundant assignment of __index?

Posted 04 December 2013 - 11:29 AM

This isn't in the right section for future notice. Someone that can move this will move it later.

for starters I would do the above the following way
MyClass = {}
MyClass.__index = MyClass

function MyClass.new(value)
  local o = {value = value}
  setmetatable(o, MyClass)
  return o
end

function MyClass:GetValue(value)
  return self.value
end


local test = MyClass.new(10)

print(test.value)
print(test:GetValue())

function test:GetValue()
  return self.value + 10
end

print(test:GetValue())



it is redundant and you don't need to do it

1) self.__index = self is redundant. just set it once at the top like I do. otherwise you are setting it a bunch.

2) it doesn't, don't do it, it is bad

3) 'new' should, IMO, not have a self parameter. I prefer the way I did it as I only talk about 'MyClass" rather than "self" which strangely reference MyClass unlike every other method.

4) I added some code after to perhaps clear up any remaining confusions

5) Just to be clear when look up in the first table fails it uses that tables metatable's __index property. __index can be either a function or a table. If it is a function then it is called with some parameters. If it is a table then lookup is preformed in it instead (which in turn may result it ITS meta table being used)
Was This Post Helpful? 2
  • +
  • -

#3 DouglasNewton  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 11-August 13

Re: [Lua] OO - why the redundant assignment of __index?

Posted 07 December 2013 - 12:13 AM

Thanks for clearing that up. I feel a bit stupid now for asking something so obvious - but I'm glad someone else could confirm this for me. :D

I fully agree that it'd be better to make the 'constructor' 'static' indeed, it's the ambiguous self that had me (and probably others new to this concept) confused originally.
Was This Post Helpful? 0
  • +
  • -

#4 wwwraith  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 27-May 16

Re: [Lua] OO - why the redundant assignment of __index?

Posted 27 May 2016 - 04:15 AM

Actually, the above code works only if you only create instances of MyClass. If you try to create an instance of test, you won't be able to inherit test's version of the GetValue function. You'll get MyClass' version instead. You really do need to set __index each time you create a new instance or you'll lose the chain of inheritance. Add this...

local test2 = MyClass.new(30)

print(test2:GetValue())



... to the end of the above code. Run it and you'll get:

10
10
20
30

If test2's version of GetValue were used, that last 30 would have been a 40, as test2:GetValue(30) would have added 10 to the argument passed. To be fair it actually looks like it should be redundant and I was confused about this as well, but I managed to stumble across this POST in the Lua forums which explains it. It turns out that writing the code that way is a memory hack, using only two tables instead of three (the post explains it much better than I would here). It's more clear if you write it this way:

MyClass = {} -- baseclass

function MyClass:new()       
	local o = {}
        local o_mt = { __index = self }
	setmetatable(o, o_mt ) 
	return o
end



o = the new object table
o_mt = the metatable for o which contains the __index field that tells Lua where to look for fields that are missing in o. It gets set in the following line.

When you see it like this, it's much more clear that the original code was using self as both the parent class and the metatable holding the __index for the child (o). This works but it's really confusing. You can also see how leaving it out...

__index = self

...would break the chain. The code previous to the last post was pointing everything at MyClass so was only good for instances of MyClass. The code that I've used for very simple OOP in Lua is:

Class = {}

function Class:new(...)
  o = {}
  setmetatable(o, {__index = self})
  if self.init then self:init(...) end
  return(o)
end



This is a little tighter as it creates the metatable anonymously in the call to setmetatable. It also automatically calls an init function if created for the object and passes any arguments passed to new. It's worked for me so far, to any depth of inheritance I've used. And it's less likely to generate confusion.

It must be noted however that this is a very simple version of OOP for Lua and lacks many of things associated with classic OOP.
Was This Post Helpful? 0
  • +
  • -

#5 wwwraith  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 6
  • Joined: 27-May 16

Re: [Lua] OO - why the redundant assignment of __index?

Posted 27 May 2016 - 04:35 AM

My bad. The last code example in my last post contained an error. It should have been:

Class = {}
 
function Class:new(...)
  o = {}
  setmetatable(o, {__index = self})
  if o.init then o:init(...) end    --line to fix
  return(o)
end



Was This Post Helpful? 0
  • +
  • -

Page 1 of 1