Object oriented programming with Luart

Luart supports a wide range of object-oriented programming (OOP) concepts out of the box, including multilevel inheritance, polymorphism, encapsulation, etc.

Object

Objects are at the heart of OOP with Luart. Objects are specialized tables, made up of fields and methods. The difference with a Lua table is that an object makes it possible to create (or rather "instantiate") a value (called "instance") from this object, i.e. made up of the same fields and methods.

Objects are created using the global function Object().

  • Objects can have fields of any value (strings, other Object values, functions...).
  • Object fields are, as for tables, always accessible and public.
  • Field deletion is done by assigning anilvalue.
  • Field access is done with ' . ', or ' : ' for methods, or '[ ]'
  • An object has a type of "Object"
  • By convention, Luart use capital letters for objects definitions

Instantiation

Instantiation is the process of creating a value from an object. An object thus acts as a type, defining the capabilities of the value from its fields and methods.

Instantiation is simple with Luart : just call the previously defined object, which will return a new instance.

  • Instances have a type defined by their object name : "File", "Window",...

Constructor and destructor

Under the hood, the instantiation calls a specific object method to construct the instance called constructor. When defined, the constructor method of an object is used to initialize instances.

Conversely, when Lua destroys the instance (during a garbage collection cycle), the object's destructor method, if defined, is called. This allows the instance to finalize/release resources before being destroyed.

  • Instance destruction order is not predictable (it depends on garbage collection).

Iterator

An iterator is an object method that is called when using an object instance in a for..in.. loop.

At each iteration, the iterator method is called with the self value as first argument and an index value as second argument. When starting the loop, the index value is nil

Once the iterator method has computed thewanted values, it should return them with the next index as the last return value. If the first returned value is nil the loop ends. Otherwise, the iterator method is called once again with the new index, and so on...

  • The iterator() method permits to iterate over an Object using the each() function

Inheritance

Inheritance is the capability of one object ("the child") to derive or inherit the fields and methods from another object (called the "ancestor" or "parent").

With Luart, to define a child object that inherits from another parent object, you just need to use the parent object as an argument to the Object() global function.

  • Luart supports only multilevel inheritance, but can use mixins to extends objects capabilities (see below).
  • is() function is used to determine inheritance of an instance/object.
  • super() function is used to get the inherited parent object.

Mixins

A mixin is a simple Lua table that can be mixed within an object to extend its capabilites. Mixins are like interfaces, but they also implements fields, methods, and properties to enrich an object.

  • Mixins offer a simple way to share functionality between objects.
  • A mixin can encapsulate common methods and properties, without the need to repeat the same code from object to object.

Polymorphism

Polymorphism in programming refers to the use of the same field/method name across different types of objects.
Luart supports polymorphism between different objects and between inherited objects, by the possibility to redefine a field/a method at anytime.

Encapsulation

Object-oriented programming (OOP) relies heavily on encapsulation. All intrinsic data needed by the object to function correctly need to be hidden from the outside. This restriction prevents the accidental modification of data by preventing direct access to fields and methods. In this case, the data variables are referred to as private variables.

As tables in Lua, Luart does not provide true private fields for objects. But it's possible to achieve this by using the keyword local for the needed variable outside the scope of the method or property where it is manipulated (see Visibility rules in Lua).

  • Luart object encapsulation is based on Lua visibility rules.

Properties

Properties are an important concept in OOP to support encapsulation. The term property refers to a special kind of object member, which falls between a field and a method in terms of functionality. The syntax for reading and writing properties is the same as that for fields, but the calls to the 'getter' and 'setter' methods translate properties into fields.

With Luart, properties are supported by the use of getter and setter methods for an object. The name of the getter method must start by the prefix get_ followed by the property name (for example, get_time for the time property. The name of the setter method must start by the prefix set_ followed by the property name (for example, set_time for the time property.

  • A getter method is defined by the prefix get_
  • A setter method is defined by the prefix set_