Overview

Thorough explanation of the features and benefits baked into the dmc-objects module.

Table of Contents

{toc:style=disc|indent=20px|minLevel=2|exclude=Table of Contents|printable=false}

DMC Objects Benefits & Features

There are many benefits to using dmc-objects to create your object classes.dmc-objects provides:

  • a classical model of object oriented programming

    dmc_objects is structured after the classical inheritance model, thus is easy to learn and use by people with varying levels of OO experience. This also helps give a solid organizational structure when using a language that is relatively unstructured.

  • a simple structure for doing OOP in Lua and Corona SDK

    The module also abstracts the details of inheritance in Lua so that both experienced and inexperienced users of the language can focus on the code being written, and not the gory details of the language. There is no need to learn about low-level Lua constructs ( eg, metatables or __index) until you want to know. All of that detail is taken care of so you can get things done.

  • fast execution through structure and optimizations

    Because of the way Lua performs lookups for properties and methods, there can be a performance penalty when using objects with many levels of inheritance. The solution is to get an object's properties and methods as close to the object as possible (ie, ON the object instead of doing a lookup). This module can do this for you so you can get the execution speed without having to sacrifice the benefit of code organization provided by OOP.

  • a mechanism for getters and setters

    The base object model in dmc_objects was built to provide getters and setters in your custom classes! Yay, getters and setters!!! Besides making code more natural and readable, it helps your objects integrate better into the Corona SDK.

  • superClass() and superCall()

    Among other object-related methods, dmc_objects has superClass() to access an object's parent, and superCall() to call any super class method!

  • an API similar to Corona display objects

    The core Corona API has been added to the pertinent base classes in dmc_objects. This allows you to treat your objects as if they were native Corona Display Objects †.

  • object printing support

    There is flexible, built-in support to print objects during debugging.

  • simplified callbacks

† You can treat them like Corona objects 99% of the time. Don't worry, the other 1% is easy to understand. \:)

Benefits In Depth

A Classical Model of Object Oriented Programming

Lua is a prototype-based language and doesn't have any hard rules about how object oriented programming should be done. It only has a few built-in features which allow it to do OOP-like things such as resolving names on objects, whether that be properties, methods, etc.

Given the flexibility of the language, this means there are many ways to set up OOP in Lua, often dictated solely by convention. So dmc_objects strives to create a pure classical approach to OOP and also takes a stance as it pertains to working with Corona SDK.

Because it leans towards Classical OOP, it's easily approachable by those with experience with it. For those who are new to OOP, there are countless books written on the topic. All anyone needs to do is understand the concepts, then look at the way it's done in dmc_objects. Everything will be familar.

A simple structure for doing OOP in Lua and Corona SDK

One of these is that the structure simplifies setting up OOP by creating an API around Lua's method of creating objects. Here is a very simple class example ; note that none of the classes have any class properties.

There are many examples of OOP using dmc_objects, both in the examples folder which comes with the DMC Corona Library and in this wiki - [Quick Guide - dmc_objects] and [Subclass the Corona Base class].

We're only showing a class constructor which is at the top of the inheritance chain. One example in dmc_objects and the other in pure Lua.

{code:language=none|title=OOP Using dmc_objects.lua} local Objects = require( "dmc_objects" )

-- setup some aliases to make code cleaner local inheritsFrom = Objects.inheritsFrom local CoronaBase = Objects.CoronaBase

--== Class Shape - parent object

local Shape = inheritsFrom( CoronaBase )

-- that's it !!

--== Class Square - subclass of Shape

local Square = inheritsFrom( Shape )


\\

{code:language=none|title=OOP using plain Lua}

--== Class Shape - parent object

local Shape = {}
setmetatable( Shape, { __index = nil } )

function Shape:new()
    local o = {}
    setmetatable( o, { __index = self } )
    return o
end


--== Class Square - subclass of Shape

local Square = Shape:new()

function Square:new()
    local o = {}
    setmetatable( o, { __index = self } )
    return o
end

\

Functionally these two examples are fairly similar, however the dmc_objects example has abstracted a lot of the class hierarchy incantations to make it simpler.

inheritFrom creates an instance of the parent and sets the hierarchy by calling _bless() on the Class Object. It also adds some more functionality which deals with comparing classes, finding the super class, etc.

The method _bless() hides the process of setting up the base hierarchy of the group by creating an object and dealing with the Lua metatable. This method also adds the functionality to provide getters and setters.

This also means that someone unfamilar with Lua doesn't need to know about setmetatable, __index, __newindex, or any other lower-level Lua constructs just to do great things with the language.

Fast execution through organization and optimizations

The following code is the constructor for the Corona Base class. (You don't have to define one for yourself, and you'll get this one for free !!) We are using the Template Pattern to give flexibility to the way our objects are instantiated. This pattern will be similar in all instances - we only need to change the behavior by overriding the proper methods.

 {code:language=none|title=Corona Base constructor}function CoronaBase:new( options )

local o = self:_bless()
o:_init( options )
o:_createView()
o:_initComplete()

return o

end``` Using the Template Pattern gives us two benefits.

Code Organization

The first benefit is that it helps us organize our code by giving structure.

The difference with this one from the Shape examples above is the addition of the methods _init(), _createView() and _initComplete(). These methods are intended to be overridden as necessary for each custom class. The _init() will hold all of the initilization of the object properties, _createView() will perform all of the initialization for the object display, and _initComplete() will contain any necessary post-init methods or event listeners.

When working alone or in a team, all of the object's base configuration will be in these methods.

Code Execution

The second benefit we get by this setup is faster code execution. As stated previously, because of the way Lua performs lookups for properties and methods, there can be a performance penalty when using objects with many levels of inheritance. The solution is to get an object's properties and methods as close to the object as possible (ie, ON the object).

We will go over how this is achieved in dmc_objects.

h5. Shaping the Initialization

The first line recommended to have in the _init() method is this one:

{code:language=none|title=Partial _init() method}function aClass:_init()

-- be sure to call this first !
self:superCall( "_init" )
...

end``` This important line will call the entire initialization stack with the new object, all the way to the top of the inheritance chain. Stated another way, {}each and every{} _init() function will be applied to the new object. Because there is this mechanism in place to delay initialization, all of the properties will be applied directly to our new object ! If you recall, this is exactly what we stated that would make our application as fast as possible.

Speed through optimizations

We said before that OOP is achieved by being able to store both properties and methods in an object chain. The language provides us a simple, built-in mechanism to perform name lookups in the chain automatically. We also said that this lookup is a performance hit and the way to get around the hit is to store all properties and methods as close to (or ON) our object as possible.

We just showed that by following the simple rule of putting all of your property initialization in _init(), that we can easily assure all of the properties will be local on the object.

The only thing left then is the class methods. By default, these methods are always left in the inheritance chain where they were put on the class which defined (or overrode) them.

However, dmc_objects has a method which will do the same optimizations for methods as we did for properties!! (We recommend that you first run your application without doing the optimization).

Here is the code required for this optimization: {code:language=none|title=Object Method Optimization}-- here's how to optimize methods on an object

self:optimize()

-- and here's how to undo the optimization

self:deoptimize()``` That's it!!

{tip}With one line of code (and putting your properties in _init(), the framework will take care of moving all properties and methods to your object so that it can run as fast as possible!{tip} If you find that you require optimizations all of the time, you can use the following as your constructor. Note the addition of the call to _optimize().

{code:language=none|title=Optimized Constructor}function MyClass:new( options )

local o = self:_bless()
o:_init( options )
o:_createView()
o:_initComplete()

o:optimize()

return o

end```

A mechanism for getters and setters

Yes, getters and setters!

When the method _bless() is used on an object, one of the things it does is setup the mechanism to provide getters and setters.

First it creates two tables on each object called getters and setters. After it creates them, it copies references to all of the getters and setters of its parent class. This means everything will be local to the object and as fast as possible.

When you want to create a getter or setter, you simply create functions as normal, but define them in the correct table like this:

This is a totally contrived example

{code:language=none|title=Creating Getters and Setters}function MyClass.__getters:speed() return self.speed end

function MyClass.__setters:speed( value ) self.dirty = true self.speed = self.currentDirection * value end``` This simple construct gives you the ability to do this:

{code:language=none|title=Getters and Setters in Action}local myObj = MyClass:new()

myObj.speed = 45

print( myObj.speed )```

This functionality allows us to make dmc_objects act like Corona objects 99% of the time ! Like so:

{code:language=none|title=Creating Getters and Setters}function CoronaBase.getters:x() return self.display.x end function CoronaBase.setters:x( value ) self.display.x = value end```

superClass() and superCall()

coming soon

An API similar to Corona display objects

coming soon

Object printing support

coming soon

References

[http://en.wikipedia.org/wiki/Prototype-based_programming]