Module ammcore.class

Allows creating classes using metatable mechanism.

Creating a class

You can create a new class by calling create(). Unless specified, the new class will inherit Base, so you can annotate it accordingly:

class = require "ammcore.class"

--- @class Foo: ammcore.class.Base
local Foo = class.create("Foo")

function Foo:doSomething()
    print("Doing something in Foo")
end

Instantiating a class

You can now create instances of your class by calling New. Note that all class methods (i.e. methods that accept class as a first parameter, rather than a class instance) start with a capital letter:

local foo = Foo:New()

Inheriting a class

You can provide a base class to create() to inherit from it:

class = require "ammcore.class"

--- @class Bar: Foo
local Bar = class.create("Bar", Foo)

You can override methods and properties of the base class:

function Bar:doSomething()
    print("Doing something in Bar")
    -- Call the super function.
    Foo.doSomething(self)
end

Similarly, you can override New:

function Bar:New()
    -- Replace `self` with a new instance of `Bar`.
    self = Foo.New(self)
    -- Initialize the new instance.
    self.beep = "boop"
    -- Don't forget to return `self`.
    return self
end

Declaring class methods

Class methods take class as a first parameter, instead of a class instance. Lua doesn’t distinguish between normal methods and class methods, so it is possible to pass an instance to a class method:

function Foo:ClassMethod()
    print(self)
end

Foo:ClassMethod() --> prints `Foo`
Foo:New():ClassMethod() --> prints `Foo()`

Here, ClassMethod expects that self is Foo, but instead it is an instance of Foo.

To avoid errors, you can always get the class by its instance using the __class attribute:

function Foo:ClassMethod()
    self = self.__class -- Make sure we're working with a class.
    print(self)
end

Foo:ClassMethod() --> prints `Foo`
Foo:New():ClassMethod() --> also prints `Foo`

Declaring metamethods

You can declare metamethods which will be applied to class instances:

class = require "ammcore.class"

Point = class.create("Point")

function Point:New(x, y)
    self = class.Base.New(self)
    self.x, self.y = x, y
    return self
end

function Point:__tostring()
    return string.format("Point(%s, %s)", self.x, self.y)
end

print(Point:New(0, 0)) --> prints `Point(0, 0)`

Metamethods only act on class instances:

print(Point) --> doesn't call `__tostring`, just prints `Point`

Warning

You should declare all metamethods before subclassing or instantiating a class, otherwise they will not be inherited correctly.

Index

Function

create()

Create a new class. Optionally takes a base class.

isChildOf()

Check if cls inherits base.

Class

Base

Base class for all classes.

Function

ammcore.class.create(name: string, base?: ammcore.class.Base, ...: any) any

Create a new class. Optionally takes a base class.

Parameters:
ammcore.class.isChildOf(cls: ammcore.class.Base, base: ammcore.class.Base) boolean

Check if cls inherits base.

Parameters:

Class

class ammcore.class.Base

Base class for all classes.

const __name: string

Name of the class.

const __module: string

Name of the module this class was defined in.

const __fullname: string

Full name of the class.

const __index: fun(self: ammcore.class.Base, k: string): any | table<string, any>

Where to find attributes that are missing in a class instance. By default, they are searched in the class table.

You can redefine this as a function that takes a key and returns a value. Do not redefine as a table, otherwise it will not be inherited properly.

const __class: ammcore.class.Base

Always points to the class itseld.

Do not redefine, otherwise inheritance will break.

const __base: ammcore.class.Base?

Always points to the base class.

Do not redefine, otherwise inheritance will break.

classmethod New(self: <T: ammcore.class.Base>) <T: ammcore.class.Base>

Constructor.

protected classmethod __initSubclass(self: ammcore.class.Base, ...: any)

A class method that will be called whenever a new subclass is created.

Whenever a new subclass is created using this class as a base, this method is called with subclass being self. Specifically, this method is called from create(), so the subclass will not have any properties or methods present.

Parameters:

... (any) – all extra arguments passed to create().