Corona Quick Thought – Survey of Lua OOP Patterns

One of the issues that seems to confuse beginners is the bewildering variety of Object-Oriented Programming approaches possible with Lua. Though Lua itself has no native/intrinsic OOP facilities, it does offer all the raw features you need to implement something that acts like a traditional OOP language (to one degree or another).

As far as Lua is concerned, an “object” is merely yet another table containing methods and properties. Once this sinks in, it becomes clear that there are numerous ways you might create and populate such a table, as well as countless minor variations on each of the major strategies — thus the many and varied OOP approaches.

This is intended only to be a quick “survey” of some of the more common OOP strategies in Lua – particularly as it applies to Corona developers. It is not intended to be a “how to” (Google is your friend for that) so little explanation of the implementations will be provided. A thoughtful read and a bit of investigation should easily reveal each strategy’s “trick” though.

Implementations are provided in bare-minimum “do-it-yourself” form, but are completely self-contained and run-able as-is. Complete sample source code here.

Disclaimer: The sample code is meant for illustrative purposes only as material to accompany this “survey” — you are on your own if you insist on treating it as production code despite this disclaimer.

Those looking for a more polished and complete OOP system should look for one of the third-party libraries such as 30log or middleclass or others. Usage of any of these OOP libraries is not covered here. (though each such library likely follows one or more of these ‘patterns’ or variations thereof)

As a sample “case study”, each implementation below will consider a game scenerio, with two game “entities”: a “player” and an “enemy”, each with its own display object for visual representation, as well as some custom properties (fe name) and methods, as well as getters/setters (fe position) to show the approach for interfacing with the display object. the display object will just be a simple colored rectangle to eliminate the need for image files.

I’ll start with what I consider to be the simpler approaches, then move toward the more complex approaches.

1. Decorated Display Objects
Probably the simplest way to add custom behavior to a display object — just create a display object then add your custom properties and methods to it directly. This may tend to produce a lot of duplicated code if your objects are closely related, and doesn’t yet support the creation of multiple instances, but might be suitable if only a few unique “singletons” are needed.

2. Factory Function with Closures
This strategy typically develops out of the desire to eliminate some of the duplicated code that can occur with 1) above by supporting “instances”. The use of closures also offers an opportunity to support truly private members, though each individual instance still remains a bit “heavy” with its own unique copy of each method.

3. Factory Function with Closures and Statics
This strategy typically develops out of the desire to retain private closure members from 2) above, while reducing the “weight” of each individual instance by referencing a set of “static” function for non-closure members.

4A. Factory Function via Prototype
This strategy typically develops from prior “factory” methods just as a means to simplify populating a newly created instance with its members from a predefined prototype or “pattern”.

4B. Factory Function via Prototype (Alternate Syntax)
This strategy is equivalent to 4A above, just worded a bit differently where the prototype is declared. Those wishing to implement a “prototype” approach will often want to pass in some other “class” which serves as the “pattern”, and the syntax used to establish the “pattern” in this variation perhaps better illustrates that approach. (you may also want a “deep” copy, rather than the shallow one here – an implementation detail beyond the scope of this survey, just mentioned in passing)

5. Wrapper Class
This strategy typically develops once some need for more-elaborate inheritance is identified. At some point it may become more tedious to continue “decorating” display objects directly (as all previous methods have done), and instead treat the “view” (the display object) as separate from its “model” (the Lua class). Something along these lines is a typical first “baby step” implementation of metatable classes.

6. Metatable Class Inheritance
This strategy typically develops directly from the needs identified in 5) above. Now that a metatable-based class system is in place, it is now possible to consolidate shared functionality in a super-class and derived special-purpose subclasses from it.

7. Metatable Class Inheritence with Function Helper
This strategy typically develops out of an attempt to better “organize” the functionality of 6) above in preparation for an even more elaborate inheritance hierarchy. Some type of helper functions (as here) or a “base class” with similar functions, is used to create/extend classes instead of inline code. This helps prep for storing class names (for identification) or a reference to the superclass (for instanceOf or super calls) within this class creation “framework”. (if you’re still writing DIY code at this point, then it’s perhaps time to start seriously considering whether one of the third-party libraries mentioned up top might save you some effort)

8. Display Object Metatable Chaining
This strategy typically develops out of a need to “monkey patch” something deep within the internals of a Corona object. It is not typically seen in usage for more general-purpose OOP needs where a simpler decorator pattern would likely suffice. As such, the sample used throughout this post is really not an appropriate use for this strategy – it is provided merely to close out the metatable portion of this survey.

So, is this a full and complete list of all possible approaches to Lua OOP? Hah! Nope. Not even close. But it’s a pretty good start on some of the more common ‘fundamentals’ used by more elaborate approaches.

Once you grasp these ‘fundamentals’ then it becomes more obvious how you might extend them further to support other OOP concepts. (though again, as previously stated several times, there are existing third-party libraries that you might want to investigate and potentially save some development effort if you can find one that fits your needs)

I’ll suggest that there is no single best approach for all users, under all circumstances, particularly given the vast range of experience levels among Corona developers. So just select an approach that best works for you. Hopefully this survey might help a bit in weeding through those choices.