Skip to content
Bilal Bassam edited this page Feb 4, 2022 · 4 revisions

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
Clone this wiki locally