lloyAlloy on GitHub
Structs and traits
Docs

Structs and traits

Structs, traits, and impls emit the metatable pattern

Updated

An Alloy struct is a plain table that vanilla Luau can use. Fields carry defaults and read or write marks. impl adds methods. A trait is a type of signatures plus default bodies.

Alloystructs.aly
1struct Vec2
2    x: number
3    y: number = 0
4end
5impl Vec2
6    function len(self): number
7        return math.sqrt(self.x ^ 2 + self.y ^ 2)
8    end
9end
10local v = new Vec2 { x = 3, y = 4 }
Emitted Luausame line count
1local __alloy = require("@alloy") local Vec2 = {} Vec2.__index = Vec2
2
3
4 type Vec2 = typeof(setmetatable({} :: { x: number, y: number }, Vec2)) setmetatable(Vec2, { __call = function(_, f: { x: number, y: number? }): Vec2 if f.y == nil then local _y: number = 0 f.y = _y end return ((setmetatable(f, Vec2) :: any) :: Vec2) end }) function Vec2.new(f: { x: number, y: number? }): Vec2 return Vec2(f) end Vec2.__tostring = function(s) return __alloy.show_struct("Vec2", s, { "x", "y" }) end
5do
6    function Vec2.len(self: Vec2): number
7        return math.sqrt(self.x ^ 2 + self.y ^ 2)
8    end
9end
10local v = Vec2({ x = 3, y = 4 }) return nil
  • new is the only way in. new Vec2 { ... } is the fields form; a struct whose impl writes new or New takes new Vec2(...) instead. Bare Vec2 { } and Vec2(1, 2) are diagnostics.
  • @derive(Eq, Debug, Clone, Serialize) is pure codegen from the field list.
  • Operator traits map to metamethods: impl Add for Vec2 puts __add on the instance metatable.
  • Generic bounds <T: Shape> become (T & Shape) on each parameter.