Add README.md for Lua OOP and Types tutorial
This commit is contained in:
parent
b8c35952cf
commit
99278f96c1
215
README.md
Normal file
215
README.md
Normal file
@ -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.
|
||||
Loading…
x
Reference in New Issue
Block a user