Bug with copying tables.

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
jotapapel
Prole
Posts: 4
Joined: Tue Aug 18, 2020 4:17 am

Bug with copying tables.

Post by jotapapel »

Hi!

So I'm developing a game and for it I've created a little class system for lua. But when I try to use it in the LOVE engine it does not seem to work.

Code: Select all

function deepcopy(orig)
  local orig_type = type(orig)
  local copy
  if orig_type == 'table' then
    copy = {}
    for orig_key, orig_value in next, orig, nil do
      copy[deepcopy(orig_key)] = deepcopy(orig_value)
    end
    setmetatable(copy, deepcopy(getmetatable(orig)))
	else -- number, string, boolean, etc
    copy = orig
  end
  return copy
end

local function class(prototype)
	local function metaclass(self, k, v) if ({constructor = true, id = true, super = true})[k] then rawset(getmetatable(self).__index, k, v) end end
	local function metaobject(self, k, v) if not(({class = true, id = true})[k]) then rawset(self, k, v) end end
	local function mt(table, type, timestamp) return {__timestamp = timestamp or 0, __index = table, __type = type, __tostring = function() return type .. tostring(table):sub(6) end, __newindex = function(self, k, v) pcall((type == 'class') and metaclass or metaobject, self, k, v) end} end
	local table = {
		prototype = prototype,
		constructor = function(self, ...) end,
		id = function(self, object) return tostring(object):sub(8) end,
		new = function(self, ...)
			local table = setmetatable({class = self}, {__index = self.prototype})
			table.id = self:id(table); self.constructor(table, ...)
			return setmetatable({}, mt(table, 'object', love.timer.getTime()))
		end,
		implements = function(self, interface, static)
			local interface = deepcopy(interface)
			local table = (static or false) and self or getmetatable(self).__index.prototype
			for k, v in pairs(interface) do rawset(table, k, v) end
			return self
		end,
		extend = function(self, prototype)
			local super = deepcopy(self)
			local index = getmetatable(super).__index
			local table = {super = self}
			for k, v in pairs(prototype) do rawset(index.prototype, k, v) end
			for k, v in pairs(index) do rawset(table, k, v) end
			for k, v in pairs(super) do rawset(table, k, v) end
			return setmetatable({}, mt(table, 'class'))
		end
	}
	return setmetatable({}, mt(table, 'class'))
end

local interface = {
	test = {
		slot = 0xc1,
		set = function(self, val) self[self.slot] = val end
	}
}

local original = class{}:implements(interface, true)
original.test:set(3)

local clone = original:extend{}
clone.test:set(8)

print(original.test, original.event[original.test.slot])
print(clone.test, clone.event[clone.test.slot])
The result of the print statements in other Lua compilers is the following:

Code: Select all

table: 0x1d2e820
table: 0x1d2d330
But in LOVE it outputs both tables as the same one, meaning that changing the value of one also changes the value of the other.

here's the example: https://repl.it/@JosMM2/simple-class#main.lua

help :(
User avatar
zorg
Party member
Posts: 3444
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Bug with copying tables.

Post by zorg »

I tried it with the love2d version of repl.it, and (while i'm not sure which version they have, or what lua backend that uses), it behaved the same as how it did with the lua interpreter through your link... that said, while the löve version shouldn't matter, maybe luajit does something differently than vanilla lua that messes with your code, which i honestly couldn't read through.

A simpler deepcopy implementation should definitely work though, at least.
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
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: Bug with copying tables.

Post by pgimeno »

I get this when running the above snippet:

Code: Select all

lua: copytab.lua:61: attempt to index field 'event' (a nil value)
(I get the same in Lua, LuaJIT and Löve).
jotapapel
Prole
Posts: 4
Joined: Tue Aug 18, 2020 4:17 am

Re: Bug with copying tables.

Post by jotapapel »

I've changed the implementation now with deepcopy and it works fine.

This is the version I'm currently using if anyone is interested.
class.lua
(3.33 KiB) Downloaded 270 times
User avatar
ivan
Party member
Posts: 1911
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: Bug with copying tables.

Post by ivan »

Yea, your code is hard to read so it may be good to look into the existing OO libraries out there.
Here is a simple one that I wrote myself - it's simple but very rarely would you need anything more sophisticated.
It's not good practice to use "table" as a variable or argument name:

Code: Select all

local table =

Code: Select all

local function encapsulate(table, prototype, ...)
Because "table" is already a well-known global variable.
In general, iterating all the key-value pairs of a table can be avoided if you use metatables efficiently.
I see a some unnecessary use of the "next" keyword too.
Also, note that your "deep-copy" clone function will crash with cycles where a table reference itself.
Post Reply

Who is online

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