Module std.prototype.container
Container Prototype.
This module supplies the root prototype object from which every other object is descended. There are no classes as such, rather new objects are created by cloning an existing object, and then changing or adding to the clone. Further objects can then be made by cloning the changed object, and so on.
The functionality of a container based object is entirely defined by its
metamethods. However, since we can store any object in a container,
we cannot rely on the __index
metamethod, because it is only a
fallback for when that key is not already in the container itself. Of
course that does not entirely preclude the use of __index
with
containers, so long as this limitation is observed.
When making your own prototypes, derive from prototype.container.prototype
if you want to access the contents of your containers with the []
operator, otherwise from prototype.object.prototype if you want to access
the functionality of your objects with named object methods.
Prototype Chain
table
`-> Container
Objects
prototype | Container prototype. |
Metamethods
prototype:__call (...) | Return a clone of this container and its metatable. |
prototype:__pairs () | Return an in-order iterator over public object fields. |
prototype:__tostring () | Return a compact string representation of this object. |
Module Functions
mapfields (new, src[, map={}]) | Return new with references to the fields of src merged in. |
Objects
- prototype
-
Container prototype.
Fields:
- _init table or function object initialisation (optional)
- _type string object name (default "Container")
Usage:
local Container = require "prototype.container".prototype local Graph = Container { _type = "Graph" } local function nodes (graph) local n = 0 for _ in pairs (graph) do n = n + 1 end return n end local g = Graph { "node1", "node2" } assert (nodes (g) == 2)
Metamethods
- prototype:__call (...)
-
Return a clone of this container and its metatable.
Like any Lua table, a container is essentially a collection of
field_n = value_n
pairs, except that field names beginning with an underscore_
are usually kept in that container's metatable where they define the behaviour of a container object rather than being part of its actual contents. In general, cloned objects also clone the behaviour of the object they cloned, unless...When calling prototype.container.prototype, you pass a single table argument with additional fields (and values) to be merged into the clone. Any field names beginning with an underscore
_
are copied to the clone's metatable, and all other fields to the cloned container itself. For instance, you can change the name of the cloned object by setting the_type
field in the argument table.The
_init
private field is also special: When set to a sequence of field names, unnamed fields in the call argument table are assigned to those field names in subsequent clones, like the example below.Alternatively, you can set the
_init
private field of a cloned container object to a function instead of a sequence, in which case all the arguments passed when it is called/cloned (including named and unnamed fields in the initial table argument, if there is one) are passed through to the_init
function, following the nascent cloned object. See the mapfields usage example below.Parameters:
- ... arguments to prototype's _init, often a single table
Returns:
-
prototype
clone of this container, with shared or
merged metatable as appropriate
Usage:
local Cons = Container {_type="Cons", _init={"car", "cdr"}} local list = Cons {"head", Cons {"tail", nil}}
- prototype:__pairs ()
-
Return an in-order iterator over public object fields.
Returns:
- function iterator function
- Object self
Usage:
for k, v in pairs (anobject) do process (k, v) end
- prototype:__tostring ()
-
Return a compact string representation of this object.
First the container name, and then between { and } an ordered list of the array elements of the contained values with numeric keys, followed by asciibetically sorted remaining public key-value pairs.
This metamethod doesn't recurse explicitly, but relies upon suitable
__tostring
metamethods for non-primitive content objects.Returns:
-
string
stringified object representation
See also:
Usage:
assert (tostring (list) == 'Cons {car="head", cdr=Cons {car="tail"}}')
Module Functions
- mapfields (new, src[, map={}])
-
Return new with references to the fields of src merged in.
This is the function used to instantiate the contents of a newly cloned container, as called by __call above, to split the fields of a __call argument table into private "_" prefixed field namess, -- which are merged into the new metatable, and public (everything else) names, which are merged into new itself.
You might want to use this function from
_init
functions of your own derived containers.Parameters:
- new table partially instantiated clone container
- src table __call argument table that triggered cloning
- map
table
key renaming specification in the form
{old_key=new_key, ...}
(default {})
Returns:
-
table
merged public fields from new and src, with a
metatable of private fields (if any), both renamed according to
map
Usage:
local Bag = Container { _type = "Bag", _init = function (new, ...) if type (...) == "table" then return container.mapfields (new, (...)) end return functional.reduce (operator.set, new, ipairs, {...}) end, } local groceries = Bag ("apple", "banana", "banana") local purse = Bag {_type = "Purse"} ("cards", "cash", "id")