Skip to main content

MetaClass

Version History

Build VersionChange DateChange TypeDescription
6760422025-06-21stableCurrent version

Overview

The MetaClass module provides an advanced class creation system that uses userdata objects instead of tables as the base for instances. This approach allows for enhanced control over garbage collection and enables replacement of metamethods like __gc and __len that are normally restricted when using tables.

The system is designed to solve garbage collection quirks where metatables could be collected before userdata, potentially causing crashes.

Key Features

  • Userdata-based Objects: Uses newproxy(true) to create userdata objects instead of tables
  • Complete Metamethod Support: Full support for all Lua metamethods including __gc
  • Garbage Collection Safety: Built-in protection against premature metatable collection
  • Inheritance Support: Supports class inheritance with is_a method
  • Constructor Flexibility: Supports both base class extension and standalone constructors

Functions

MetaClass(base, _ctor)

Status: stable

Description: Creates a new MetaClass definition. Like the standard Class function but uses userdata objects as the base, allowing replacement of __gc and __len functions.

Parameters:

  • base (table|function): Either a base class to inherit from, or a constructor function if no inheritance is needed
  • _ctor (function, optional): Constructor function when base is a table

Returns:

  • (table): The class definition that can be called to create instances

Example:

-- Create a simple MetaClass with constructor
local MyClass = MetaClass(function(self, name)
self.name = name
self.created_time = GetTime()
end)

-- Create instance
local instance = MyClass("TestObject")
print(instance.name) -- "TestObject"

-- Create MetaClass with inheritance
local BaseClass = MetaClass(function(self, value)
self.base_value = value
end)

local DerivedClass = MetaClass(BaseClass, function(self, value, extra)
BaseClass._ctor(self, value)
self.extra_data = extra
end)

local derived = DerivedClass(10, "additional")
print(derived.base_value) -- 10
print(derived.extra_data) -- "additional"

Built-in Methods

instance:is_a(klass)

Status: stable

Description: Checks if an instance is of a specific class or inherits from it. Traverses the inheritance chain to find matches.

Parameters:

  • klass (table): The class to check against

Returns:

  • (boolean): true if the instance is of the specified class or inherits from it

Example:

local BaseClass = MetaClass(function(self) end)
local DerivedClass = MetaClass(BaseClass, function(self) end)

local instance = DerivedClass()
print(instance:is_a(DerivedClass)) -- true
print(instance:is_a(BaseClass)) -- true

Metamethods

The MetaClass system provides comprehensive metamethod support through internal metafunctions:

Object Access Metamethods

MetamethodDescriptionUsage
__indexProperty/method accessobj.property or obj[key]
__newindexProperty assignmentobj.property = value
__lenLength operator#obj
__pairsIteration with pairsfor k,v in pairs(obj)
__ipairsIteration with ipairsfor i,v in ipairs(obj)
__nextNext function overridenext(obj, key)

Lifecycle Metamethods

MetamethodDescriptionUsage
__gcGarbage collectionAutomatic cleanup
__eqEquality comparisonobj1 == obj2

Arithmetic Metamethods

MetamethodDescriptionUsage
__addAdditionobj + other
__subSubtractionobj - other
__mulMultiplicationobj * other
__divDivisionobj / other
__modModuloobj % other
__powExponentiationobj ^ other
__unmUnary minus-obj
__concatConcatenationobj .. other
__callFunction callobj(args)
__ltLess thanobj < other
__leLess than or equalobj <= other

Implementation Details

Garbage Collection Protection

The module uses a weak reference table to prevent premature collection of metatables:

local metatable_refs = setmetatable({}, {__mode = "k"})

When creating instances, the metatable is stored in this weak table to ensure it remains accessible until the userdata is collected.

Metamethod Resolution

Each metamethod first checks for custom implementations in the instance's metatable (mt._), then falls back to the class definition (mt.c). This allows both instance-specific and class-level metamethod customization.

Length Operator Protection

The __len metamethod includes recursion protection to prevent infinite loops:

if __len and not mt._insidelen then
mt._insidelen = true
local result = __len(t)
mt._insidelen = false
return result

Usage Guidelines

When to Use MetaClass

Use MetaClass instead of regular Class when you need:

  • Custom garbage collection behavior (__gc metamethod)
  • Precise control over object lifecycle
  • Override length operator (__len) behavior
  • Enhanced metamethod functionality

Required Helper Functions

When working with MetaClass instances, use the meta* versions of standard functions:

  • metapairs() instead of pairs()
  • metanext() instead of next()
  • metaipairs() instead of ipairs()
  • metarawget() instead of rawget()
  • metarawset() instead of rawset()

Performance Considerations

MetaClass instances have slightly more overhead than regular tables due to:

  • Userdata object creation
  • Metatable reference management
  • Metamethod resolution chain

Use MetaClass only when the advanced features are necessary.

Common Patterns

Custom Garbage Collection

local ResourceClass = MetaClass(function(self, resource_id)
self.resource_id = resource_id
self._cleanup_needed = true
end)

-- Define custom cleanup
ResourceClass.__gc = function(self)
if self._cleanup_needed then
-- Custom cleanup logic
CleanupResource(self.resource_id)
end
end

Custom Length Behavior

local ContainerClass = MetaClass(function(self)
self.items = {}
self.capacity = 10
end)

ContainerClass.__len = function(self)
return #self.items
end

local container = ContainerClass()
print(#container) -- Uses custom __len

Technical Notes

  • MetaClass instances are userdata objects, not tables
  • All data is stored in the metatable's _ field
  • Class definition is stored in the metatable's c field
  • Supports full inheritance chain traversal
  • Thread-safe for read operations