10
\$\begingroup\$

I've discovered (and written) a way to object oriented programming in lua in a functional fashion instead of the standard metatable method. It carries much more functionality (no pun intended) but I'm afraid it might dent performance. My goal is to experiment with servers written in lua and I wanted to use this OOP solution. Anyways here's my class.lua which holds the functions for creating new objects and subclasses.

local classes = setmetatable({}, {__mode = "k"}) -- Allow the GC to empty this as needed.

function class(f, super)
    classes[f] = {super = super}
end

function new(f, obj, ...)
    local fenv = getfenv(f)
    if type(obj) ~= "table" then
        error("bad argument: expected table, got " .. type(obj) , 2)
    end

    if classes[f] and classes[f].super then
        new(classes[f].super, obj, ...)
        local super = obj
        obj = setmetatable({}, { __index = super })
        obj.super = super
    else
        setmetatable(obj,{__index = fenv})
    end

    obj.this = obj
    setfenv(f, obj)
    f()
    setfenv(f, fenv)

    if obj.init then
        obj.init( ... )
    end

    return obj
end

Usage is fairly simple. Take the following example:

function Person()
    local privateVar = math.random()
    age, name, gender = nil, nil, nil

    function init(age, name, gender)
        this.age = age
        this.name = name
        this.gender = gender
    end

    function getPrivateVar()
        return privateVar
    end
end

And to create the object

obj = new(Person, {}, "John", 30, "male")

Subclassing is also simple

function Female()
    function init(name, age)
        super.init(name, age, "female")
    end
end

class(Female, Person)

Note that you only have to call a function to make something a class if you want to subclass.

When you call new, you pass in the class, object, and arguments. The object's metatable is set to have an index of the class's original environment. Then the super is determined and created. Then the class function is run to create all instance values. Next, init is called.

One advantage of this over metatables are that other code can't change the class and have it change all instances of that class that already exist and that will exist. Now the only way to do something like that is to swizzle and hack around in environments to make sure all references to the class refer to the hacker's dummy class.

On top of that, it supports private variables. Just declare them locally in your class function and you're good to go.

But I'm wondering if the fact that it creates all the instance methods once for every instantiation is going to cause performance problems. Will this eat memory? What can go wrong here?

Also, there's an issue. While this supports multiple inheritance, if you call a super method, and the super calls a method, it will call the method of the super class, not the instantiated class. Any ideas how to make it call from the instantiated class?

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

Even though this kind of inheritance is perfectly valid example of OOP designing in language like Lua; it is considered a bad practice of programming.

According to Programming in Lua on Object-Oriented Programming.

This kind of function is almost what we call a method. However, the use of the global name Account inside the function is a bad programming practice.

  1. This function will work only for this particular object.
  2. Even for this particular object the function will work only as long as the object is stored in that particular global variable; if we change the name of this object, withdraw does not work any more.

The example they've used to depict is also quite to the point and small.

You should also take a look at how they've explained creation of classes; their inheritance; public, private and protected datatypes/variables and many other OOP concepts using metamethods and tables depending on their usage.

Here's the index of OOP concepts incorporated in Lua.

Useful Links

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.