32 lines of goodness, yet another OO lib

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
ishkabible
Party member
Posts: 241
Joined: Sat Oct 23, 2010 7:34 pm
Location: Kansas USA

Re: 32 lines of goodness, yet another OO lib

Post by ishkabible »

what he said :P
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: 32 lines of goodness, yet another OO lib

Post by Robin »

I like to dispute the "goodness" of this library.

It does not actually work.

As long as you don't use :extends(), it's fine (as far as I can tell), but when you do, all hell breaks loose.

Code: Select all

setmetatable(mt_class, {__index = parent})
This line. This line is the source of most misery. You see, when you create an instance of the subclass and try to access a property that doesn't exist, this happens:

Code: Select all

instance.blah -- doesn't exist!
subclass.blah -- doesn't exist!
mt_class.blah -- doesn't exist!
superclass.blah -- doesn't exist!
mt_class.blah -- doesn't exist!
Error, stuck in a loop. (Lua sez "loop in gettable".)
This is more fucked up than you might think, by the way: think of the implications for multiple subclasses:

Code: Select all

class "A"{}
class "B"{}
class "C":extends(A){}
class "D":extends(B){} -- surprise, C is now a subclass of B instead of A!
Actually, it is even worse. The last class passed to :extends would be the "parent" of every class existing now and to be made later, even itself. Luckily, we don't have to worry about that, since it doesn't work either way.

That's not goodness, this is just plain wrong.

This works:

Code: Select all

local mt_class = {}

local function define(class, members)
   class.__members__ = class.__members__ or {}
   for k, v in pairs(members) do
      class.__members__[k] = v
   end
   function class:new(...)
      local newvalue = {}
      for k, v in pairs(class.__members__) do
         newvalue[k] = v
      end
      setmetatable(newvalue, {__index = class})
      if newvalue.__init then
         newvalue:__init(...)
      end
      return newvalue
   end
end

function mt_class:extends(parent)
   self.super = parent
   setmetatable(self, {__index = parent, __call = define})
   parent.__members__ = parent.__members__ or {}
   return self
end

function class(name)
    local newclass = {}
   _G[name] = newclass
   return setmetatable(newclass, {__index = mt_class, __call = define})
end
EDIT: it works, but it is still wrong. Look closely at the behavior of __members__ for subclasses.

Replacing the first line of define by

Code: Select all

   class.__members__ = {}
   if class.super then
      for k, v in pairs(class.super.__members__) do
         class.__members__[k] = v
      end
   end
should do it.
Help us help you: attach a .love.
User avatar
ishkabible
Party member
Posts: 241
Joined: Sat Oct 23, 2010 7:34 pm
Location: Kansas USA

Re: 32 lines of goodness, yet another OO lib

Post by ishkabible »

hmm, i should have tested further, this is embarrassing.
User avatar
Ruirize
Prole
Posts: 20
Joined: Tue Dec 13, 2011 9:02 pm
Location: England
Contact:

Re: 32 lines of goodness, yet another OO lib

Post by Ruirize »

I know this post is old, and I know there are better libraries out there, but I like the looks of this one, as it looks really close to what I'm looking for.

Does this fix work as advertised?
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: 32 lines of goodness, yet another OO lib

Post by Robin »

I'm not sure. I wrote the fix, but I'm not maintaining this "library".

May I suggest Slither as an alternative?
Help us help you: attach a .love.
User avatar
ishkabible
Party member
Posts: 241
Joined: Sat Oct 23, 2010 7:34 pm
Location: Kansas USA

Re: 32 lines of goodness, yet another OO lib

Post by ishkabible »

Robins fixes work, I wrote this as a spur of the moment thing after I saw someone else do it and didn't give it much other consideration(e.g. it's not being maintained). I did it badly as robin pointed out. If you use this lib and report any bugs I'll see what I can do to fix them. Of course, Slither has a very similar(if not even more elegant) syntax and is probably more stable. You might be better off with it instead.
User avatar
Ruirize
Prole
Posts: 20
Joined: Tue Dec 13, 2011 9:02 pm
Location: England
Contact:

Re: 32 lines of goodness, yet another OO lib

Post by Ruirize »

I can assure you that I prefer the way that you've set up in these 32 lines :)

It's perfect for what I need, thank you.
User avatar
ishkabible
Party member
Posts: 241
Joined: Sat Oct 23, 2010 7:34 pm
Location: Kansas USA

Re: 32 lines of goodness, yet another OO lib

Post by ishkabible »

1 possible thing that might happen; if you declare a default value as a table then change it in the instance it will change it for all other subsequent instances. basic rule of thumb is to not declare default values as tables. I'm working on an improved version that will fix this(and stay within 32 LOC of properly formatted code!)
User avatar
Ruirize
Prole
Posts: 20
Joined: Tue Dec 13, 2011 9:02 pm
Location: England
Contact:

Re: 32 lines of goodness, yet another OO lib

Post by Ruirize »

It'd be great if you could update it :)
User avatar
ishkabible
Party member
Posts: 241
Joined: Sat Oct 23, 2010 7:34 pm
Location: Kansas USA

Re: 32 lines of goodness, yet another OO lib

Post by ishkabible »

well I incorporated Robin's fixes but getting a deep copy in there is a bit tougher. here is Robin's fixes crammed into well formatted 32 lines. I'll work on deep copies of default values later.

Code: Select all

 
local mt_class = {}

function copy(tin)
    local tout = {}
    for k, v in pairs(tin) do
		tout[k] = v
	end
	return tout 
end

local function define(class, members)
	class.members = copy(class.super and class.super.members or {})
	for k, v in pairs(members) do
		class.members[k] = v
	end
	function class.new(...)
		local t = setmetatable(copy(class.members), {__index = class})
		local blah = t.__init and t:__init(...)
		return t
	end
end

function mt_class:extends(parent)
	self.super = parent
	parent.members = parent.members or {}
	return setmetatable(self, {__index = parent, __call = define})
end

function class(name)
	_G[name] = {}
	return setmetatable(_G[name], {__index = mt_class, __call = define})
end
Post Reply

Who is online

Users browsing this forum: No registered users and 192 guests