Warning: this is an htmlized version!
The original is across this link,
and the conversion rules are here.
-- eoo.lua: Edrx'x simple OO scheme.
-- This file:
--   http://angg.twu.net/blogme4/eoo.lua.html
--   http://angg.twu.net/blogme4/eoo.lua
--            (find-blogme4file "eoo.lua")
-- Author: Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2011jan12
-- 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")
-- Inheritance:     (find-dn5 "eoo.lua")
-- Announcement: http://lua-users.org/lists/lua-l/2011-03/msg00975.html

-- «.test-eoo»	(to "test-eoo")


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



-- 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 "~/blogme4/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
--
--]==]






-- Local Variables:
-- coding:             raw-text-unix
-- ee-anchor-format:   "«%s»"
-- End: