Implementation of overriding functions but keeping previous functionality

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.
Post Reply
User avatar
ThatBonk
Prole
Posts: 11
Joined: Thu May 23, 2019 6:11 pm

Implementation of overriding functions but keeping previous functionality

Post by ThatBonk »

Hello,

I've been stumbling in some of my more bigger projects into a big problem.

I use OOP to keep my code sorted and come across no big deal on smaller classes I am creating.

What comes off as a big problem though is keeping the functionality of the old function I want to override.
Whenever I implement an abstract function to try to keep the old function's properties, problems stack up even more,
as my brain can't simply comprehend anymore which function to use and name.

In summary with the following example:

Is there a way to call for 'function Dimension:update(dt)' without 'Pointer:update(dt)' losing its functionality?

Code: Select all

-- Class Pointer --
function conNewPointer()
  local Pointer = {}

  -- Variables --
  Pointer.x = 0
  Pointer.y = 0

  function Pointer:update(dt)
    -- Original update --
    self.x = self.x + 1
    -- Compensating for not being able to keep old properties --
    self:abstractUpdate(dt)
  end
  
  -- Too complex abstract function to try to compensate. --
  function Pointer:abstractUpdate(dt)
    
  end

  return Pointer
end

-- Class Dimension --
function conNewDimension()
  local Dimension = conNewPointer()
  
  -- Using this function to compensate for not being able to keep old commands of previous function,
  -- when calling Dimension:update(dt) --
  function Dimension:abstractUpdate(dt)
    -- Inconvinient solution. --
    self.y = self.y + 1
  end
  
  return Dimension
end
Thanks for any help and suggestions.
sphyrth
Party member
Posts: 260
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by sphyrth »

Since your coding style looks similar to mine, try this:

Code: Select all

-- Class Pointer --
function conNewPointer()
  local Pointer = {}

  -- Variables --
  Pointer.x = 0
  Pointer.y = 0
  
  function Pointer:abstractUpdate(dt)
  end
  
  function Pointer:update(dt)
    Pointer.x = Pointer.x + 1
    Pointer:abstractUpdate(dt)
  end

  return Pointer
end

-- Class Dimension --
function conNewDimension()
  local Dimension = conNewPointer()
  
  function Dimension:abstractUpdate(dt)
    Dimension.y = Dimension.y + 1
  end
  
  return Dimension
end

Disclaimer: There are coding conventions I might be breaking because:
#1

Code: Select all

-- I don't know when to use periods
function SampleClass.update(dt) end
-- and when to use colons
function SampleClass:update(dt) end
#2

Code: Select all

-- I ALWAYS do this
SampleClass.x = SampleClass.x + whatever
-- Because I never know when to use this
self.x = self.x + whatever
User avatar
ThatBonk
Prole
Posts: 11
Joined: Thu May 23, 2019 6:11 pm

Re: Implementation of overriding functions but keeping previous functionality

Post by ThatBonk »

Thanks for the suggestion.

Now there's also a problem that comes with it:

The next inheritance will have yet another abstractUpdate2(dt). I'm trying to avoid having so many update functions, that stack on the same name and grow like a long list.

Is there really no way around it?
sphyrth
Party member
Posts: 260
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by sphyrth »

I don't really understand it as of now, but maybe you wanted something like this.

Code: Select all

-- Class Pointer --
function conNewPointer()
  local Pointer = {}

  -- Variables --
  Pointer.x = 0
  Pointer.y = 0
  
  function Pointer:update(dt)
    Pointer.x = Pointer.x + 1
  end

  return Pointer
end

-- Class Dimension --
function conNewDimension()
  local Dimension = conNewPointer()
  
  function Dimension:update(dt)
    Dimension.x = Dimension.x + 1
    Dimension.y = Dimension.y + 1
  end
  
  return Dimension
end
Dimension:update(dt) overrides Pointer:update(dt) but you can create another conNewPointer() and its original update(dt) function isn't affected.
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by zorg »

I'd use metatables because it makes this whole OOP thing infinitely simpler in lua.
Also allows you to call the original parent class' methods if you want to (super or whatever you'd want to name it)
Or really any other table... also, you are not separating class stuff and instance stuff either...

Code: Select all

-- Class Point --
local Point = {}
Point.__index = Point

function Point:update(dt)
	-- Point's update
	self.x = self.x + 1
end

function newPoint()
	local p = {
		x = 0
	}

	setmetatable(p, Point)

	return p
end



-- Class Line --
local Line = {}
Line.__index = Line

-- Note: If you want Line instances to fall back to point methods automatically if Line doesn't have them, then you'd need to do something like this instead:
--[[
local Line = {}
local mtLine = {__index = Point}
Line.__index = mtLine
setmetatable(Line, mtLine)
--]]

function Line:update(dt)
	Point.update(self) -- Calls other "Class"'s update function containing only the x param updater.
	-- Line's update
	self.y = self.y + 1
end

function newLine()
	local l = newPoint()

	-- Add second dimension field
	l.y = 0

	-- Fix the metatable so it's a line instead of a point.
	setmetatable(l, Line)

	return line
end
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
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by zorg »

sphyrth wrote: Wed Jun 03, 2020 11:04 am
Disclaimer: There are coding conventions I might be breaking because:
-- I don't know when to use periods
-- and when to use colons
...
-- Because I never know when to use this
Tell me if this is helpful or not, been working on it:
https://github.com/zorggn/love-discord- ... axsugar.md
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.
sphyrth
Party member
Posts: 260
Joined: Mon Jul 07, 2014 11:04 am
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by sphyrth »

zorg wrote: Wed Jun 03, 2020 12:54 pm Tell me if this is helpful or not, been working on it:
https://github.com/zorggn/love-discord- ... axsugar.md
Oh, thanks! :awesome:
That basically hit two birds with one stone. All I need now is a bit of breaking bad habits.
User avatar
ThatBonk
Prole
Posts: 11
Joined: Thu May 23, 2019 6:11 pm

Re: Implementation of overriding functions but keeping previous functionality

Post by ThatBonk »

zorg wrote: Wed Jun 03, 2020 12:51 pm I'd use metatables because it makes this whole OOP thing infinitely simpler in lua.
Also allows you to call the original parent class' methods if you want to (super or whatever you'd want to name it)
Or really any other table... also, you are not separating class stuff and instance stuff either...

Code: Select all

-- Class Point --
local Point = {}
Point.__index = Point

function Point:update(dt)
	-- Point's update
	self.x = self.x + 1
end

function newPoint()
	local p = {
		x = 0
	}

	setmetatable(p, Point)

	return p
end



-- Class Line --
local Line = {}
Line.__index = Line

-- Note: If you want Line instances to fall back to point methods automatically if Line doesn't have them, then you'd need to do something like this instead:
--[[
local Line = {}
local mtLine = {__index = Point}
Line.__index = mtLine
setmetatable(Line, mtLine)
--]]

function Line:update(dt)
	Point.update(self) -- Calls other "Class"'s update function containing only the x param updater.
	-- Line's update
	self.y = self.y + 1
end

function newLine()
	local l = newPoint()

	-- Add second dimension field
	l.y = 0

	-- Fix the metatable so it's a line instead of a point.
	setmetatable(l, Line)

	return line
end
Thanks a lot! That is exactly what I needed. Also, thumbs up to your github page about tables.

Is there more to learn about metatables than to set and get them?
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Implementation of overriding functions but keeping previous functionality

Post by zorg »

Yes, they can modify indexing of existing and non-existing keys in tables and quite a lot of operators as well (e.g. how arithmetical ones like +,-,*,/,^ or logical ones like ==,~=,<=,< work on tables) unfortunately i can't go over all of that now, at work.

Btw, not really my github page, doing it as a PR to this one: https://github.com/pfirsich/love-discord-faq

Maybe someone else can explain mt-s nicely, but there are a few resources you can look at:
http://lua-users.org/wiki/MetamethodsTutorial
https://www.lua.org/pil/13.html
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.
Post Reply

Who is online

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