|
Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
-- eoo.lua: Edrx'x simple OO scheme.
-- This file:
-- http://angg.twu.net/dednat5/eoo.lua.html
-- http://angg.twu.net/dednat5/eoo.lua
-- (find-dn5 "eoo.lua")
-- (find-tkdiff "~/blogme4/eoo.lua" "~/dednat5/eoo.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2011nov21
-- License: GPL3
--
-- A very simple object system.
-- The metatable of each object points to its class,
-- and classes are callable, and act as creators.
-- New classes can be created with, e.g.:
-- Circle = Class { type = "Circle", __index = {...} }
-- then:
-- Circle {size = 1}
-- sets the metatable of the table {size = 1} to Circle,
-- and returns the table {size = 1} (with its mt modified).
--
-- Originally from: (find-angg "LUA/canvas2.lua" "Class")
-- A tool: (find-angg ".emacs.templates" "class")
-- «.test-eoo» (to "test-eoo")
-- «.box-diagram» (to "box-diagram")
Class = {
type = "Class",
__call = function (class, o) return setmetatable(o, class) end,
}
setmetatable(Class, Class)
otype = function (o) -- works like type, except on my "objects"
local mt = getmetatable(o)
return mt and mt.type or type(o)
end
-- Code for inheritance (2011nov21), untested...
-- The examples of usage for this are coming soon!
over = function (uppertable)
return function (lowertable)
setmetatable(uppertable, {__index=lowertable})
return uppertable
end
end
ClassOver = function (upperclassmt)
return function (lowerclass)
setmetatable(upperclassmt.__index, {__index=lowerclass.__index})
return Class(upperclassmt)
end
end
-- dump-to: tests
-- «test-eoo» (to ".test-eoo")
--[==[
-- Here is a detailed explanation of how this works.
-- Using the notation of the __mt patch, at:
-- http://angg.twu.net/__mt.html
-- (find-TH "__mt")
-- we can rewrite the code above as:
-- Class = { type = "Class",
-- __call = \ (class, o) => o.__mt = class end }
-- Class.__mt = Class
-- otype = \ (o) local mt = o.__mt; => mt and mt.type or type(o) end
-- Here is a test for it (note: it does _not_ require a patched Lua).
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
ee_dofile "~/dednat5/eoo.lua" -- this file
Vector = Class {
type = "Vector",
__add = function (V, W) return Vector {V[1]+W[1], V[2]+W[2]} end,
__tostring = function (V) return "("..V[1]..","..V[2]..")" end,
__index = {
norm = function (V) return math.sqrt(V[1]^2 + V[2]^2) end,
},
}
v = Vector {3, 4} -- v = { 3, 4, __mt = Vector}
w = Vector {20, 30} -- w = {20, 30, __mt = Vector}
print(v) --> (3,4)
print(v + w) --> (23,34)
print(v:norm()) --> 5
print( type(v)) --> table
print(otype(v)) --> Vector
print( type("")) --> string
print(otype("")) --> string
-- So we have:
--
-- Class = {
-- type = "Class",
-- __call = \(class, o) => o.__mt = class end,
-- __mt = Class
-- }
-- Vector = {
-- type = "Vector",
-- __add = \(V, W) => {V[1]+W[1], V[2]+W[2]} end,
-- __tostring = \(V) => "("..V[1]..","..V[2]..")" end,
-- __index = { norm = \(V) => math.sqrt(V[1]^2+V[2]^2) end },
-- __mt = Class
-- }
--
-- and we can use reductions to understand "Vector {3, 4}" and "v:norm()":
--
-- v = Vector {3, 4}
-- --~-> Vector({3, 4})
-- --~-> Vector.__mt.__call(Vector, {3, 4})
-- --~-> Class.__call(Vector, {3, 4})
-- --~-> (\(class, o) => o.__mt = class end)(Vector, {3, 4})
-- --~-> (\() => {3, 4}.__mt = Vector end)()
-- --~-> {3, 4, __mt = Vector}
--
-- and:
--
-- v:norm()
-- --~-> {3, 4, __mt=Vector}:norm()
-- --~-> {3, 4, __mt=Vector}.norm ({3, 4, __mt=Vector})
-- --~-> {3, 4, __mt=Vector}.__mt.__index.norm({3, 4, __mt=Vector})
-- --~-> Vector.__index.norm({3, 4, __mt=Vector})
-- --~-> (\(V) => math.sqrt(V[1]^2+V[2]^2) end)({3, 4, __mt=Vector})
-- --~-> (\() => math.sqrt( 3^2+ 4^2) end)()
-- --~-> (\() => 5 end)()
-- --~-> 5
-- «box-diagram» (to ".box-diagram")
-- Here is a box diagram that explains more clearly what we get after
-- running "v = Vector {3, 4}; w = Vector {20, 30}".
--
-- <fcal> = function (class, o) return setmetatable(o, class) end
-- <fadd> = function (V, W) return Vector {V[1]+W[1], V[2]+W[2]} end
-- <ftos> = function (V) return "("..V[1]..","..V[2]..")" end,
-- <fnor> = function (V) return math.sqrt(V[1]^2 + V[2]^2) end
--
-- /---+---\ /---+----\
-- v = | 1 : 3 | w = | 1 : 20 |
-- | 2 : 4 | | 2 : 30 |
-- \mt-+---/ \mt-+----/
-- : ............/
-- : /
-- vv
-- /--------------+----------\
-- Vector = | "type" : "Vector" |
-- | "__add" : <fadd> |
-- | "__tostring" : <ftos> | /--------+--------\
-- | "__index" : * .......> | "norm" : <fnor> |
-- \mt------------+----------/ \--------+--------/
-- :
-- v
-- /----------+---------\
-- Class = | "type" : "Class" |
-- | "__call" : <fcal> |
-- \mt--------+---------/
-- : ^
-- \..../
--
-- If we define precisely what is a "Class box" we can represent the
-- main part of the diagram above more compactly, as:
--
-- /---+---\ /---+----\
-- v = | 1 : 3 | w = | 1 : 20 |
-- | 2 : 4 | | 2 : 30 |
-- \mt-+---/ \mt-+----/
-- : ............/
-- : /
-- vv
-- /-Class--------+----------\
-- Vector = | "type" : "Vector" |
-- | "__add" : <fadd> |
-- | "__tostring" : <ftos> |
-- +--------------+----------|
-- | "norm" : <fnor> |
-- \--------------+----------/
--
--]==]
-- Local Variables:
-- coding: raw-text-unix
-- ee-anchor-format: "«%s»"
-- End: