lua_oop/README.md

216 lines
3.9 KiB
Markdown

# 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.