# Lua OOP + Types Tutorial This project provides a small OOP layer with Python-like ergonomics and a set of Python-inspired types. Contents - OOP: class definitions as functions, inheritance, visibility, auto-bound methods - Types: Int, Float, Str, Bool, Tuple, List (linked), Queue, Stack, Dict, Set --- ## OOP quick start The OOP system lets you define a class as a function that receives `cls`. Instances are created by calling the class itself. ```lua oop = require("oop/oop") function Animal(cls) function cls.__init(this, name) this.name = name end function cls.speak(this) print(this.name .. " makes a noise.") end end function Dog(cls) cls.inherit(Animal) function cls.speak(this) cls.super.speak(this) print(this.name .. " barks!") end end local d = Dog("Milo") d.speak() ``` ### How instance calls work Methods are defined with dot syntax and explicit `this`: ```lua function cls.move(this, dx, dy) this.x = this.x + dx this.y = this.y + dy end ``` Calls also use dot syntax. `this` is auto-passed for you: ```lua obj.move(1, 2) ``` Do not use `:` calls with this system because methods are already auto-bound. --- ## Visibility (public / protected / private) Visibility is checked when reading or writing members. Use `cls.visibility` or `Visibility`: ```lua function User(cls) cls.setattr(cls, "name", nil, cls.visibility.PUBLIC) cls.setattr(cls, "password", nil, cls.visibility.PRIVATE) cls.method("set_password", function(this, pw) this.password = pw end, cls.visibility.PRIVATE) function cls.__init(this, name, pw) this.name = name this.password = pw end end ``` - public: accessible everywhere - protected: accessible in the class and subclasses - private: accessible only inside the class itself Errors show where the access was attempted and from which class. --- ## Inheritance Use `cls.inherit(ParentClass)`: ```lua function Base(cls) function cls.hello(this) print("base") end end function Sub(cls) cls.inherit(Base) function cls.hello(this) cls.super.hello(this) print("sub") end end ``` `cls.super` exposes the direct parent only. --- ## Types module All types live in `oop/types.lua`: ```lua local Types = require("oop/types") ``` ### Primitive types (immutable) Primitives are immutable after construction: - `Int` - `Float` - `Str` - `Bool` - `Tuple` You can call a primitive to get its value, and use `.copy()` to create a new one. ```lua local i = Types.Int(42) print(i()) -- 42 print(i.copy()) -- new Int ``` Tuple stores items immutably: ```lua local t = Types.Tuple({ 1, 2, 3 }) print(t()) -- immutable items proxy print(t.get(2)) -- 2 ``` ### Mutable types - `List` (linked list) - `Queue` - `Stack` - `Dict` - `Set` Examples: ```lua local l = Types.List({ "a", "b" }) l.append("c") print(l, #l, l.get(2)) local q = Types.Queue({ 1, 2 }) q.enqueue(3) print(q.dequeue(), q.peek()) local st = Types.Stack({ 9, 8 }) st.push(7) print(st.pop(), st.peek()) local d = Types.Dict({ one = 1, two = 2 }) print(d.get("two")) d.set("three", 3) print(#d) local s = Types.Set({ "x", "y" }) s.add("z") print(s.has("x"), #s) ``` --- ## Dunder methods (operators) Classes support common Lua metamethods. If you do not override them, they raise an error. Example vector: ```lua function Vec2(cls) function cls.__init(this, x, y) this.x = x this.y = y end function cls.__add(a, b) return Vec2(a.x + b.x, a.y + b.y) end function cls.__tostring(this) return "Vec2(" .. this.x .. ", " .. this.y .. ")" end end local v = Vec2(1, 2) + Vec2(3, 4) print(v) ``` --- ## Notes and tips - Class functions with capitalized names are auto-wrapped into classes when assigned to globals. - Methods must be called with dot syntax, not colon syntax. - `new(Class, ...)` still works, but `Class(...)` is preferred.