This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Kingdaro's profile picture

A nice, small class implementation.

Started by Kingdaro, 02 May 2013 - 09:12 AM
Kingdaro #1
Posted 02 May 2013 - 11:12 AM
So in the process of making my [REDACTED], I thought I'd go ahead and share my nice, simple little class system/function with you guys.

http://pastebin.com/VMgD3GZf
Spoiler
function class(obj)
  obj = obj or {}
  obj.init = obj.init or function() end

  function obj:new(...)
    local instance = setmetatable({__class = obj}, {__index = obj})
    return instance, instance:init(...)
  end

  function obj:extend(t)
    t = t or {}
    for k,v in pairs(obj) do
      if not t[k] then
        t[k] = v
      end
    end
    return class(t)
  end

  return setmetatable(obj, {__call = obj.new})
end

Classes are created by calling the class method.

MyClass = class{
  some = 'vars';
  a = 1;
  b = 2;
  c = 3;
}

-- Class variables are optional
MyClass = class()
MyClass.some = 'vars'
MyClass.a = 1
MyClass.b = 2
MyClass.c = 3

To create an instance, just call the class table.

obj = MyClass()
print(obj.a, obj.b, obj.c) --> 123

In the class, the :init() method is called when you create a class. You can use this to set variables at instance creation.

MyClass = class()

function MyClass:init(name)
  self.name = name or 'NoName'
end

obj = MyClass('LUAAA')
print(obj.name) --> LUAAA

Inheritance is done by using the :extend() method on classes.


Parent = class{
  foo = 'bar';
}

Child = Parent:extend{
  bar = 'baz';
}
print(Child.foo) --> bar
print(Child.bar) --> baz

Finally, instances store their parent class in the __class variable, so you can check the types of certain instances.

Object = class()

obj = Object()
print(obj.__class == Object) --> true

As a usage example, here are some silly classes.

Thing = class()

function Thing:speak()
  print 'I am a thing.'
end

Organism = Thing:extend{
  kind = '';
}

function Organism:init(kind)
  self.kind = kind or self.kind
end

function Organism:speak()
  Thing.speak(self)
  print 'A living thing, in fact.'
  print('I am a '..self.kind)
end

Person = Organism:extend{
  name = '';
  kind = 'human';
}

function Person:init(name)
  self.name = name or self.name
end

function Person:speak()
  Organism.speak(self)
  print('My name is '..self.name)
end

unknown = Thing()
unknown:speak() --> I am a thing.

frog = Organism('frog')
frog:speak()
--> I am a thing.
--> A living thing, in fact.
--> I am a frog

bob = Person('Bob')
bob:speak()
--> I am a thing.
--> A living thing, in fact.
--> I am a human
--> My name is Bob

Hopefully this'll teach you a thing or two about good ol' OO. :)/>/>/>/>/>
Jarle212 #2
Posted 02 May 2013 - 11:41 AM
Wery nice OOP, I might start using this methode instead of setting metatables every singel time. :)/>
GravityScore #3
Posted 02 May 2013 - 12:54 PM
Very nice!

Now add static class methods, and the ability to call the superclass init method (like Java's super function) so you don't have to go kind or self.kind for every variable :P/>
Kingdaro #4
Posted 02 May 2013 - 01:53 PM
Very nice!

Now add static class methods, and the ability to call the superclass init method (like Java's super function) so you don't have to go kind or self.kind for every variable :P/>
I'd like to avoid being like Java for the time being :lol:/>

Seriously though, you can already call superclass methods, just by using another class's method with your self.


Object = class()
function Object:init(x, y)
  self.x = x
  self.y = y
end

ChildObject = Object:extend()
function ChildObject:init(...)
  Object.init(self, ...)
end

test = ChildObject(5, 5)

I'm not entirely sure what you mean by static class methods though.
theoriginalbit #5
Posted 02 May 2013 - 02:41 PM
I'd like to avoid being like Java for the time being :lol:/>
Seriously though, you can already call superclass methods, just by using another class's method with your self.
he wants the keyword super though. Also super is in more than Java.

I'm not entirely sure what you mean by static class methods though.
static are variables or methods that belong to the actual type (or in this case api/file) as opposed to the object. Link
Edited on 02 May 2013 - 12:59 PM
Sammich Lord #6
Posted 02 May 2013 - 02:52 PM
static are variables or methods that belong to the actual type (or in this case api/file) as opposed to the object. Link
Your link is broken but I think I found the link you were looking for http://msdn.microsoft.com/en-us/library/98f28cdx%28v=vs.80%29.aspx
theoriginalbit #7
Posted 02 May 2013 - 02:59 PM
Your link is broken but I think I found the link you were looking for http://msdn.microsof...v=vs.80%29.aspx
Indeed that is the one that I attempted to link. :)/> thanks.
Kingdaro #8
Posted 02 May 2013 - 03:35 PM
Ah, so a static variable would be like a class variable in ruby, then? If I understand you correctly, you could just have the variable in your class and change it accordingly. If you wanted to go the extra mile, you could just declare the count variable nil when the instance is created.


Window = class{
  count = 0
}

function Window:init()
  Window.count = Window.count + 1
  self.count = nil
end

a = Window()
b = Window()
c = Window()
print(a.count, b.count, c.count) --> ...nothing
print(Window.count) --> 3

That or just have the variable separate from the class itself, that would probably be the best approach.

he wants the keyword super though.

Not necessary, because you can just use a class method with an alternate self, as I've demonstrated. Not trying to make a full-fledged class system here, just some convenient OO.

Also super is in more than Java.

I'm aware. The super keyword is in moonscript too. :D/>

EDIT: Ahaha, I made a goof. Even if you set the count variable to nil in the example I've made, it still prints the count because the instance is indexing the base class, which has a count variable. So yeah, just make it a separate variable.
Jarle212 #9
Posted 02 May 2013 - 04:42 PM
That or just have the variable separate from the class itself, that would probably be the best approach.

Metatables could solve that problem :)/> if used in a different way than instantiation.
Kingdaro #10
Posted 02 May 2013 - 05:04 PM
Could, yes.

Should? Nah.
Jarle212 #11
Posted 02 May 2013 - 05:20 PM
Could, yes.

Should? Nah.

:PPPP
theoriginalbit #12
Posted 02 May 2013 - 08:51 PM
That or just have the variable separate from the class itself, that would probably be the best approach.
Metatables could solve that problem :)/> if used in a different way than instantiation.
I didn't say that, you quoted the wrong person.
Jarle212 #13
Posted 03 May 2013 - 08:47 AM
That or just have the variable separate from the class itself, that would probably be the best approach.
Metatables could solve that problem :)/> if used in a different way than instantiation.
I didn't say that, you quoted the wrong person.


Sorry, I deleted the wrong quote tags :P/>. Fixed now
Eric #14
Posted 04 May 2013 - 04:44 AM
Nice and concise.

Here's my more complex version, inspired by how python handles classes and descriptors: https://github.com/eric-wieser/pylua

There are some examples there at the bottom of the page.
Mads #15
Posted 04 May 2013 - 11:27 AM

Object = class()

obj = Object()
print(obj.__class = Object) --> true

Of course it would print true. You are making a statement, which is always true.
Kingdaro #16
Posted 04 May 2013 - 12:59 PM

Object = class()

obj = Object()
print(obj.__class = Object) --> true

Of course it would print true. You are making a statement, which is always true.

Thanks for pointing out the typo instead of being a smartass about it.

For the record, it would actually error instead of printing anything.
Mads #17
Posted 04 May 2013 - 01:06 PM
Oh. Silly Lua and it's restrictions!