From 99278f96c11764a18bfb8e49e30feb5b47b275c1 Mon Sep 17 00:00:00 2001 From: lordlogo2002 Date: Thu, 1 Jan 2026 18:37:06 +0100 Subject: [PATCH] Add README.md for Lua OOP and Types tutorial --- README.md | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..384f3a5 --- /dev/null +++ b/README.md @@ -0,0 +1,215 @@ +# 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.