Last active
October 17, 2016 04:40
-
-
Save marcoonroad/ac3d7f6c7bf4141e2bbaf26e3c54d8b7 to your computer and use it in GitHub Desktop.
Proof of concept of this post: https://marcoonroad.github.io/Kinds-of-Delegation/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local prototype = { } | |
local reason = { } | |
local metatable = { } | |
prototype.erase = '__please_erase_this_property_in_lookup_rules__' | |
prototype.protected = true | |
reason.protected = "Protected against delegated mutation [%s <- %s] by [protected = true]!" | |
reason.missing = "No such property/value for selector [%s]!" | |
reason.mutation = "Unable to perform property addition/mutation [%s <- %s]!" | |
reason.extend = "Receiver object is protected by [protected = true] against [extend] invocation!" | |
reason.erase = "The identifier [erase] is reserved!" | |
local function lookup (self, selector) | |
if rawequal (selector, 'erase') then return prototype.erase end | |
-- avoids infinite recursion -- | |
local parent = rawget (self, 'parent') | |
while not rawequal (parent, nil) do | |
local value = rawget (parent, selector) | |
if rawequal (value, nil) then | |
parent = rawget (parent, 'parent') | |
elseif rawequal (value, prototype.erase) then | |
break | |
else | |
return value | |
end | |
end | |
parent = rawget (self, 'parent') | |
if rawequal (parent, nil) or rawequal (parent, prototype.erase) then | |
return prototype.missing (self, selector) | |
else | |
-- late-bounded error handling -- | |
return self: missing (selector) | |
end | |
end | |
local function detection (self, selector, value) | |
if rawequal (selector, 'erase') then | |
error (reason.erase) | |
end | |
return rawset (self, selector, value) | |
end | |
local function split (self, selector, value) | |
if self.parent.protected then | |
selector = tostring (selector) | |
value = tostring (value) | |
error (reason.protected: format (selector, value)) | |
elseif rawequal (selector, 'erase') then | |
error (reason.erase) | |
else | |
self.parent[ selector ] = value | |
end | |
end | |
local function immutable (_, selector, value) | |
selector = tostring (selector) | |
value = tostring (value) | |
error (reason.mutation: format (selector, value)) | |
end | |
-- short wrappers for invocations -- | |
local function same (self, that) | |
return self: same (that) | |
end | |
local function pretty (self) | |
return self: pretty ( ) | |
end | |
metatable.cloning = { | |
__metatable = '<cloning-metatable>', | |
__index = lookup, | |
__newindex = detection, | |
__eq = same, | |
__tostring = pretty, | |
} | |
metatable.extending = { | |
__metatable = '<extending-metatable>', | |
__index = lookup, | |
__newindex = split, | |
__eq = same, | |
__tostring = pretty, | |
} | |
metatable.immutability = { | |
__metatable = '<immutability-metatable>', | |
__index = lookup, | |
__newindex = immutable, | |
__eq = same, | |
__tostring = pretty, | |
} | |
-- value sharing delegation -- | |
function prototype: clone (structure) | |
if not rawequal (structure.erase, nil) then | |
error (reason.erase) | |
end | |
local object = { } | |
for selector, value in pairs (structure) do | |
object[ selector ] = value | |
end | |
object.parent = self | |
return setmetatable (object, metatable.cloning) | |
end | |
-- property sharing delegation -- | |
function prototype: extend (structure) | |
if self.protected then error (reason.extend) end | |
if not rawequal (structure.erase, nil) then | |
error (reason.erase) | |
end | |
local object = { } | |
for selector, value in pairs (structure) do | |
object[ selector ] = value | |
end | |
object.parent = self | |
return setmetatable (object, metatable.extending) | |
end | |
-- safe-aliasing -- | |
function prototype: immutable ( ) | |
local structure = { } | |
structure.parent = self | |
return setmetatable (structure, metatable.immutability) | |
end | |
-- pretty-printing -- | |
function prototype: pretty ( ) | |
return '<object>' | |
end | |
-- equality -- | |
function prototype: same (that) | |
return rawequal (self, that) | |
end | |
-- error handling -- | |
function prototype: missing (selector) | |
selector = tostring (selector) | |
error (reason.missing: format (selector)) | |
end | |
setmetatable (prototype, metatable.cloning) | |
return prototype: immutable ( ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment