Classes - SinisterRectus/Discordia GitHub Wiki
The Lua language does not have classes, but it does have all of the tools needed to write them. Discordia uses a custom class system that was written explicitly to encapsulate data provided by Discord in intuitive, efficient structures.
The class
module used by Discordia is available to users in the main Discordia module. The class module is both the module table and a callable class constructor.
local discordia = require('discordia')
local class = discordia.class
Constructing Classes and Objects
All Discordia classes must be uniquely named and must have an __init
method. UpperCamelCase
is used for class names while lowerCamelCase
is used for public instances, properties, and methods.
local Apple = class('Apple') -- construct a new class
function Apple:__init(color) -- define the initializer
...
end
local apple = Apple('red') -- call the class table to instantiate a new object
Properties
Discordia enforces a "protected" property policy. All new properties written directly to class objects must be prefixed with an underscore. Directly accessing underscored properties outside of the class definitions is not recommended. Additionally, to avoid potential compatibility issues, writing custom properties to pre-defined Discordia classes is not recommended.
local Apple = class('Apple')
function Apple:__init(color)
self._color = color -- define a "protected" property
end
Because of this underscore policy, Discordia classes also have getters and setters that can be used to define public properties. These are empty tables and should be populated by functions where getters return a value and setters modify a property. Note that an explicit self
must be passed for these functions.
local Apple, get, set = class('Apple') -- multiple return values
function Apple:__init(color)
self._color = color
end
function get.color(self) -- define a getter
return self._color
end
function set.color(self, color) -- define a setter
self._color = color
end
With getters and setters, you can indirectly get/access and set/mutate protected (underscored) properties without having to use a method. More importantly, if a setter is not defined for a specific property, Discordia will prevent users from overwriting that property. Note Discordia itself never uses setters, but the option is available for people who want to make their own classes.
local apple = Apple('red')
print(apple.color) -- 'red'
apple.color = 'green'
print(apple.color) -- 'green'
Member Methods
Member methods are defined and called using Lua's colon notation so that an implicit self
is passed to the function.
local Apple = class('Apple')
function Apple:__init(color)
self._color = color
end
function Apple:getColor() -- define a member method
return self._color
end
local user = Apple('red')
print(user:getColor()) -- 'red'
Static Methods
Static methods are defined and called using Lua's dot notation. No implicit (or explicit) self
is required for static methods.
local colors = {'red', 'yellow', 'green'}
function Apple.random() -- returns a random apple object
return Apple(colors[math.random(#colors)])
end
Inheritance
Discordia classes support single and multiple inheritance. Base or super classes are passed to the class constructor.
local Fruit = class('Fruit') -- Fruit is a base class
function Fruit:__init(color)
self._color = color
end
function Fruit:getColor()
return self._color
end
local Apple = class('Apple', Fruit) -- Apple inherits from Fruit
function Apple:__init(color)
Fruit.__init(self, color) -- base constructor must be explicitly called
end
local apple = Apple('red')
print(apple:getColor()) -- 'red'; method inherited from Fruit
Utilities
The class module contains a variety of tables and functions that may be useful to regular users.
classes
Table of all defined classes, indexed by name.
local Color = class.classes.Color
local Channel = class.classes.Channel
local TextChannel = class.classes.TextChannel
isClass
Function that returns true only if the provided argument is a Discordia class module.
print(class.isClass(Color)) -- true
print(class.isClass(1337)) -- false
isObject
Function that returns true only if the provided argument is an instance of a Discordia class.
local color = Color(...)
print(class.isObject(color)) -- true
print(class.isObject(1337)) -- false
isSubclass
Function that returns true if the first argument is a subclass of the second argument. Note that classes are considered to be subclasses of themselves.
print(class.isSubclass(TextChannel, Channel)) -- true
print(class.isSubclass(Color, Channel)) -- false
print(class.isSubclass(Channel, Channel)) -- true
isInstance
Function that returns true if the first argument (an object) is an instance of the second argument (a class). Note that inheritance is considered.
local channel = TextChannel(...)
print(class.isInstance(channel, TextChannel)) -- true
print(class.isInstance(channel, Channel)) -- true
print(class.isInstance(channel, Color)) -- false
type
Function that returns the type of the provided argument. If the argument is a Discordia object, then this will return the name of its class; otherwise, it will return the result of calling Lua's global type
function.
print(class.type(color)) -- 'Color'
print(class.type(1337)) -- 'number'
profile
Function that returns the number of each class instance currently alive (ie, not garbage collected) in table form.
local data = class.profile()
for name, count in pairs(data) do
print(name, count)
end