Object inheritance

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
zorg
Party member
Posts: 2620
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Object inheritance

Post by zorg » Sat Jul 13, 2019 3:22 pm

Yeah, i usually prefer to completely separate classes and instances (whether with or without any kind of inheritance is in play), to me it feels more clean, and i don't need to think about mixing both behaviours into one table, but ultimately, it's just a matter of preference.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.

User avatar
ivan
Party member
Posts: 1454
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Object inheritance

Post by ivan » Sat Jul 13, 2019 4:48 pm

Oh I think I finally understand. Here is a clearer view of the code:

Code: Select all

A = {}
function A:new()
  local o = {}
  setmetatable(o, self)
  self.__index = self
  return o
end
function A:foo()
  print('A')
end
B = A:new()
function B:foo()
  print('B')
end
C = B:new()
function C:foo()
  print('C')
end

a = A:new()
b = B:new()
c = C:new()
a:foo()
b:foo()
c:foo()
It does work but it's just not very clear IMO.
My issue is with the merging of metatables and interfaces or "classes" into a single table.
This results in weird stuff like "self.__index = self" which is executed everytime you call "new".
In theory this line doesn't need to be executed every time you create an "instance".
I'm not crazy with modifying the metatable/interface after an object is created.
It could lead to weird bugs like:

Code: Select all

function A:new()
  local o = {}
  setmetatable(o, self)
  self.__index = self
  o:baz() -- won't work until B:baz() is defined
  return o
end
B = A:new()
function B:baz()
  print('B')
end

TheHUG
Citizen
Posts: 51
Joined: Sun Apr 01, 2018 4:21 pm

Re: Object inheritance

Post by TheHUG » Sat Jul 13, 2019 5:29 pm

Yes that's true about self.__index, you could set A.__index = A, and then do the same whenever you define a new class, or if you prefer to keep the metatable and the superclass separate you could define local metaA = {__index=A} and set that to be the metatable of subclasses. It's an additional thing to remember to do, and a little bit of code duplication, while the efficiency savings very small unless you spawn multiple instances per frame. I suppose you could define a function to initialize a table, set its index to the superclass you want, and define its __index attribute (or the separate metatable). I might give that a try next time.

That's a good point, if you want something in initialization to depend on something implemented by the subclass you can't do it cleanly like this. The webpage I initially got this from actually did this:

Code: Select all

function A:new(o)
    local o = o or {}
    setmetatable(o, self)
    self.__index = self
    -- more code e.g
    o:baz()
    return o
end
I didn't see why you may want to provide o at first, but now I can see why it might be helpful, you can do:

so that you can do

Code: Select all

B = {}
function B:baz()
  print('B')
end
A:new(B)
hmm... though now I write it out I don't like the look of it. I'll play around with that more if I run into a situation where I want some part of initialization to depend on a method of the subclass.

edit:

Code: Select all

B = A:new({
  baz=function(self)
     ...
   end})
looks alright to me

User avatar
ivan
Party member
Posts: 1454
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Object inheritance

Post by ivan » Sat Jul 13, 2019 5:50 pm

The most confusing part is that you're doing multiple things through the :new() function.
I would split that into two functions: :new() and :inherit() then the code would look much more clear.

TheHUG
Citizen
Posts: 51
Joined: Sun Apr 01, 2018 4:21 pm

Re: Object inheritance

Post by TheHUG » Sat Jul 13, 2019 6:22 pm

That's a pretty good idea

User avatar
pgimeno
Party member
Posts: 1690
Joined: Sun Oct 18, 2015 2:58 pm

Re: Object inheritance

Post by pgimeno » Sun Jul 14, 2019 11:32 am

That's indeed the approach that 4vZEROv posted in the previous page (except 'inherit()' is called 'extend()' in 4vZEROv's version).

User avatar
raidho36
Party member
Posts: 1804
Joined: Mon Jun 17, 2013 12:00 pm

Re: Object inheritance

Post by raidho36 » Sun Jul 14, 2019 9:38 pm

In my class implementation, inheritance workflow is set up like this:

Code: Select all

local baseclass = Class ( "baseClassName" )
function baseclass:foo ( ) ...
local derivedclass = baseclass:extend ( "derivedClassName" )
function derivedclass:bar ( ) ...
Internally, it copies over all data from base class into derived class. Not having to do multiple __index hops to find inherited functions and values makes it run a lot faster, and the memory footprint increase is microscopic (it's only the class definition, not individual instances). However, this also means that it won't pick up changes made to the base class after the inheritance call, so one should only inherit from complete classes.

Post Reply

Who is online

Users browsing this forum: Bing [Bot], Exabot [Bot] and 3 guests