Class Mechanism

Poly uses Lua metatables to simulate a class mechanism. The following example class illustrates Poly’s Class API:

 1-- require Poly's Class API
 2local Class = require('__poly__.Class')
 3
 4-- == Define a new class called ExampleClass ======================================
 5local ExampleClass = Class:new('examples.ExampleClass')
 6
 7-- define ExampleClass's "new" function (a.k.a. its constructor)
 8function ExampleClass:new(param1, param2)
 9    -- return a new object of this class (metatable is automatically set by Poly)
10    return {
11        attr1 = param1,
12        attr2 = param2
13    }
14end
15
16-- define a class method, e.g., a setter for attr1
17function ExampleClass:set_attr1(attr1)
18    self.attr1 = attr1
19end
20
21-- create a new object of ExampleClass
22local my_example_object = ExampleClass:new(1, 'foo')
23-- call class method 'set_attr1' with argument 5 on my_example_object
24my_example_object:set_attr1(5)
25
26
27-- == Define a new class that is derived from ExampleClass ========================
28local DerivedClass = Class:new('examples.DerivedClass', ExampleClass)
29
30-- override "new" of ExampleClass
31function DerivedClass:new()
32    -- call super class constructor
33    return ExampleClass:new(2, 'bar')
34end
35
36-- create a new object of DerivedClass
37local my_derived_object = DerivedClass:new()
38-- call inherited class method 'set_attr1' with argument 10 on my_derived_object
39my_derived_object:set_attr1(10)

Some additional notes on the Class API:

  • The class method new is a special member function. It is the class’ constructor and, if defined, has to return a new instance of the class. It can optionally take arguments. You do not have to set instance’s metatable yourself, Poly takes care of that for you.

  • To make the class mechanism work, all calls to member and static member functions of a class have to use the colon notation, e.g., ExampleClass:new(1, 'foo') and my_example_object:set_attr1(5). Definitions of class methods have to use the colon notation as well, e.g., function ExampleClass:set_attr1(attr1) ....

  • The first parameter to Class:new is the class’ identifier. It can be any unique string, but usually should be the class’ name prefixed with the class’ path, e.g., examples.ExampleClass in this example, because example class is defined in a file in the examples folder. Adding the class’ path as prefix allows to have multiple classes with the same name.

  • The Class:new function takes an optional second argument base_class. This allows for class inheritance, when passing another previously defined class. The derived class provides all functions of the base class. Defining functions in the derived class overrides the corresponding function in the base class. Note that when overriding the new function, you are responsible for correctly initializing the base class object, e.g., by calling the base class constructor.

  • Poly may persist class instances in Factorio’s global table, e.g. for event handling, so it is generally a good idea to only store compatible types in class instances, e.g. numbers, strings, LuaGuiElements, and not functions, for example.