Page 1 of 1

Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 10:38 am
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.

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 11:04 am
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

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 11:22 am
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?

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 12:27 pm
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.

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 12:51 pm
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

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 12:54 pm
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

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 1:21 pm
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.

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 1:46 pm
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?

Re: Implementation of overriding functions but keeping previous functionality

Posted: Wed Jun 03, 2020 1:55 pm
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