Author

Document date

We denote x.p(i) the ith application of .p to x (we put x.p(0) = x). A subset C ⊆ X is called a
A structure is said to be locally finite if its every finitely generated substructure is finite. For a (partial) monounary algebra (X, .p) it means that for every x ∈ X, the set {x, x.p(1), x.p(2), …, } is finite.
Proposition: Let (X, .p ) be a connected (total) monounary algebra.
The following picture shows a pseudotree with a 4element pseudoroot C. An arrow x → y means x.p = y.
(2)←(1) 

(1)←(2) 


i.e. .p⊆) satisfying (∗),  is the smallest function on X (w.r.t.(X,≤) is the reflexive transitive closure of (X, .p ), (∗)  
(3)←(1) 
 (1)←(3) 


i.e. .p is the smallest relation on X
satisfying (∗), the
reflexive transitive reduction of (X,≤) (a.k.a Hasse diagram), 
(X,≤) is the reflexive transitive closure of (X, .p) (∗). 
Notes:
reflexive transitive closure ofwhen referring to algebraic forests of form (2) or (3).
algebraic forestis equivalent to that of a rooted forest [].
Proposition:
A structure (X, .p
, r) is an algebraic tree iff (X, .p ) is a pseudotree with the pseudoroot being the singleton set {r}.Proposition:
Note: We always aim at C being the closest approximation of D as possible so that the data structure is as little determined by transitions as possible.
Primary objects 
Secondary objects


Classive objects
alias Classives 
Classes 
Eigenclasses 

Terminative objects
alias Terminatives 
Terminals 
Class
has no instances.
(This is in contradiction with most of present Ruby literature.)
(O, .terminative?, .primary?)
where
O
is a set of (all) objects,
.terminative?
and .primary?
are boolean attributes of objects
indicating whether an object is terminative resp. primary.
(O, .ec, .pr, .sc, r, c)
where
O
is a set of (all) objects.
.ec
is a total function between objects,
x.ec
is called the eigenclass of x
.
.pr
is a total function between objects,
x.pr
is called the primary object of x
.
.sc
is a partial function between objects,
x.sc
(if defined) is called the superclass of x
.
r
is an object, called the inheritance root.
c
is an object, called the instance root
or metaclass root
(by c
is a shorthand for r.ec.sc
).
x
is terminative if
x.pr
is not r
and x.pr.sc
is not defined.
.terminal?
, .class?
and .eigenclass?
,
respectively).
x.sc(i)
(resp. x.ec(i)
)
denotes the i
th application of .sc
(resp. .ec
)
to x
(we allow 0
th application
whenever the 1
st application is defined).
.sc
(with the reflexive closure only applied to nonterminals)
is denoted ℍ
and called the (.sc
) inheritance.
.ec
is denoted ℙ
and called the primorder.
(S1~1) 
The structure (O, .ec, .pr) is a
primorder algebra.
We will apply established notation and terminology, in particular, definition of .ce and .eci .

(S1~2) 
The inheritance ℍ
is an algebraic tree on nonterminals, its root is r .
More specifically, for every object x ,

(S1~3) 
.sc and .ec are commutative in the following sense:
if( .sc links per .ec chains are parallel.) 
(S1~4) 
.sc preserves primary objects on nonterminals, i.e.
x.sc is a class for every nonroot class x .

(S1~5) 
.ec.sc preserves primary objects on terminals, i.e.
x.ec.sc is primary for every terminal x .

(S1~6) 
.sc maps to classives, i.e.
for every object x ,
if x.sc is defined then x.sc.pr is a class.

(S1~7) 
c equals
r.ec.sc and is different from r
(this prevents the degenerate case of r being the only class).

(S1~8) 
r.ec is the only object x satisfying
x.sc == c .

Proposition:
c
is a class.
r
is a class.
x
, x.sc
is a class.
x
, y
are classes such that
x.sc(i) == y
for some i > 0
then
we say that x
is a subclassof y
.
By a previously mentioned proposition,
the reflexive closure of the subclassof relation is an algebraic tree on classes.
x
,
the eigenclass index of x
,
denoted x.eci
,
is the unique i
such that x == x.pr.ec(i)
.
Proposition:
The superclass operator .sc
decrements the eigenclass index on
(all) eigenclasses of terminals and on (all) eigenclasses of the inheritance root
r
.
On other objects, the index is preserved.
I.e. for every object y
for which y.sc
is defined,
y.sc.eci == y.eci  1
if y.pr
equals either r
or some terminal,
y.sc.eci == y.eci
otherwise.
.sc
links are skewin case (a) and
uprightin case (b).
x
we denote by x.hancs
the list of inheritance ancestors of x
.
More specifically,
.hancs
is a partial function from the set
O
of objects to the set of lists of objects defined by
x.hancs
is defined iff x
is nonterminal,
x.hancs[i] == y
iff x.sc(i) == y
.
x
by
x.hancestors
,
i.e. x.hancestors
equals x.hancs
without eigenclasses.
c
,
i.e.
a metaclass is a nonterminal object x
such that x.hancs
contains c
.
A metaclass is said to be
Note: The explicit/implicit terminology is redundant. We could use the primary/secondary terminology established in the 2x2 nomenclature.
Observations:
c
is the only explicit metaclass.
r.ec
.
.ec_sc_pr
the restriction of .ec.sc.pr
to the set O.pr ∖ {r}
of all primary objects except the
inheritance root.
Obviously, .ec_sc_pr
is an algebraic tree.
For every primary x
,
x.ec_sc_pr == x.sc
if x
is a class,
x.ec_sc_pr == x.class == x.ec.sc
if x
is a terminal (*).
.ec_sc_pr
the primary inheritance.
Note:
(*)
The .class
map is defined later.
.ec.sc.pr
to just the set O.pr
of
all primary objects we obtain the Ruby's front pseudotree.
Its pseudoroot is the set of helix classes introduced in the next section.
The primary inheritance can be then called the front tree.
The picture from the
Pseudotree introductory section
provides a visualization of these 2 structures.
(O_{₀₁}, .sc, .ec)
of an S1 structure such that
O_{₀₁}
is the set of objects with eigenclass index equal
to 0
or 1
,
.sc
is the restriction of the superclass partial map to
O_{₀₁}
,
.ec
is the restriction of the eigenclass map to primary objects
–
so that .ec
is only partial in S1_{₀₁}
(and is a bijection between primary objects and first eigenclasses).
Proposition: Up to isomorphism, an S1 structure is uniquely determined by its S1_{₀₁} substructure.
S
is generated from an empty set using S
's constants and functions.
Applied to an S1 structure,
the least substructure is generated from the inheritance root r
using .sc
, .ec
and .pr
.
We call the minimum S1 substructure Ruby helix. The name comes from the fact that the substructure resembles a helical threading of a rightinfinite screw. The inheritance corresponds to the helix curve, the primorder corresponds to imaginary lines parallel to the screw axis. This is stated more precisely as follows.
Proposition:
c.hancs
and
their .ec
chains.
In particular, Ruby helix contains no terminals.
.sc
is injective.
n
be the number of helix classes,
i.e. n = c.hancs.length
.
Then x.ce == x.sc(n)
x
.
Class < Module < Object < BasicObject
.
In particular,
BasicObject
is the inheritance root r
.
The following table shows basic notation and terminology for helix classes.
Document notation  Description  Ruby name 
r 
the inheritance root  BasicObject 
¤ 
the conventional inheritanceroot  Object 
m 
the metamodule root  Module 
c 
the instance root / metaclass root  Class 
.sc
function is indicated by
arrows ↖ and
↑,
the .ec
function by the
→ arrows.
Objects A
, B
and b
are assumed to be created by the code
class A; end; class B < A; end; b = B.new
(cf.[])
Primary objects (alias classes and terminals) 
Secondary objects (alias eigenclasses) 

Eigenclass index →  0  1  2  …  
(Duplicately presented row)  •Class  →  •  →  •  →  …  
4row cylinder skew seam →  ↖  ↖  ↖  
Classives  •BasicObject  →  •  →  •  →  …  
↑  ↑  ↑  
•Object  →  •  →  •  →  …  
↑ ↑ ↑ ↑ ↑ ↑ 
↑  ↑ ↑ ↑ ↑ ↑ ↑ 
↑  ↑ ↑ ↑ ↑ ↑ ↑ 
↑  
•Module  →  •  →  •  →  …  
↑  ↑  ↑  
•Class  →  •  →  •  →  …  
•A  →  •  →  •  →  …  
↑  ↑  ↑  
•B  →  •  →  •  →  …  
↖  ↖  ↖  
Terminatives  •b  →  •  →  •  →  … 
.class
function alias
directinstanceof relation
.class
function maps objects to classes.
For every object x
,
x.class == x.ec.sc
if x
is terminal,
x.class == r.ec.sc
(== c
) otherwise.
Proposition:
For every object x
,
x.class
equals the entryobject
of the class subtree when traversed from the eigenclass of x
,
i.e.
x.class == x.ec.hancestors[0]
.
For objects x
, y
,
if x.class == y
then we say
that y
is the class of x
and that x
is a direct instance of y
.
The reflexive transitive closure of .class
is an algebraic tree with a 23 level structure
shown in the following table
(we use the name Class
for the instance root c
).
level members  
0 (top level)  Class 

1  Classes except Class 
Eigenclasses 
2  Terminals 
Class
has no (direct) terminal instances.
.class ◦ ℍ
.
Equivalently,
x
is an instanceof y
iff
x.class.sc(i) == y
for some i
.
Proposition:
x
is an instanceof y
iff
x.ec.hancestors
contains y
.
S_{0}, S_{1}, …,
of abstract states or just states.
The sequence itself is called an (abstract) run.
S_{0}
is the initial state.
For each state S_{i}
, we denote S_{i}.S1
its corresponding S1 structure.
In addition, we use the following notational conventions:
By saying that S → S'
is a state transition we
mean S
and S'
are abstract states
with S
appearing before S'
in the run.
We use state indices or apostrophes to distinguish between structures for
particular states,
e.g. O_{i}
denotes
the set of objects of S_{i}.S1
.
We drop underscores whenever no confusion is likely to arise,
so that O_{i}
means O_{i}
.
The following rules apply:
State transitions are substructural in the S1 structure,
i.e.
for every states S_{i} , S_{j} ,
the restriction of S_{i}.S1 and S_{j}.S1
to their common object set
O_{i} ∩ O_{j} is equal.
More specifically,
for every object x from
O_{i} ∩ O_{j} ,
 
For every consecutive states S_{i} , S_{i+1} ,
either
O_{i} ⊆ O_{i+1} or
O_{i} ⊇ O_{i+1} .
 
O_{0} ⊆ O_{i} for every
i , i.e.
the initial objects are never removed.

x
and their .ec
chains to the S1 structure.
The following must be specified, explicitly or implicitly, for each such x
:
x.ec.sc.pr
(i.e. the parent in the primary inheritance .ec_sc_pr
– necessarily a class).
x
 i.e. whether x
should be (a) a terminal or (b) a class.
X
, different from Class
,
and then creating a new object x
such that
x.ec.sc.pr == X
either by (a) instantiation of X
or (b) subclassing from X
, as in the following code:
x = X.new
.
This creates a new terminal x
.
x = Class.new(X)
.
This creates a new class x
.
y
is instantiable
if it is allowed to have instances, i.e.
in some reachable state,
x
such that x
is instanceof y
.
y
is final
if
y
has no subclasses, and
Note:
The Class
class is final (due (S1~8)).
y
is quasifinal
if
y
does not have instantiable subclasses, and
Proposition:
Class
,
quasifinal classes are those that cannot have indirect instances.
Note:
The Symbol
class is quasifinal (due (S3~4)).
Classes
Metamodules

Modules
Terminals

(m, .incs)
where
m
is a class, called the root metamodule,
.incs
is a partial function from the set
O
of objects to the set of (finite) lists of objects.
.incs
are called (own) inclusion lists.
Descendant classes of m
different from Class
are called metamodules.
Terminals that are instances of m
are modules.
An S2 structure has the following (additional) axioms:
(S2~1) 
The root metamodule m equals
the already presented helix class Module .

(S2~2) 
x.incs is defined iff x is a module or a nonterminal.

(S2~3)  Only modules can appear in inclusion lists. 
(S2~4)  A module cannot appear in its own inclusion list. 
(S2~5)  All inclusion lists are nonrepetitive (injective), i.e. no object appears more than once in the same inclusion list. 
.incs
maps includers to lists of includers.
Note that this terminology admits includers with no own includees.
Proposition:
An object is an includer iff it is an instance of Module
.
x
, y
,
if y
occurs in x.incs
then y
is called an own includee of x
and x
is called an own includer of y
.
We also say that y
is directly included in x
.
The reflexive closure, restricted to includers,
of the ownincluderof relation is denoted by
Μ
.
x
is a pure instance if it is an end userof the type system:
x
is neither a class nor an eigenclass nor a module.
≤
between includers
as (ℍ ◦ Μ) ∪ Μ
.
Recall that
ℍ
is the .sc
inheritance, and
Μ
is the reflexive closure of the ownincluderof relation.
x ≤ y
iff x
and y
are includers
such that at least one of the following is satisfied:
x == y
,
x.sc(i) == y
for some i
,
x.incs[i] == y
for some i
,
x.sc(i).incs[j] == y
for some i
, j
.
<
for the strict version of ≤
(and symbols ≥
and >
for inverses of
≤
and <
, respectively).
Proposition:
.sc
inheritance.
≤
symbol,
HM descendancy is not a partial order in general.
Neither transitivity nor acyclicity (antisymmetry of the transitive closure)
is guaranteed.
(See Inclusion anomalies for examples.)
x
, y
such that x ≤ y
,
x
not being an eigenclass implies
y
not being an eigenclass,
x
being a module implies
y
being a module.
<
to modules, i.e.
x
is an includer of y
iff x < y
and y
is a module.
y
is an includee of x
or that
y
is included in x
.
Proposition: The includerof relation is an extension of the ownincluderof relation.
.ec ◦ ≤
.
Equivalently,
x
is kind of y
iff x.ec ≤ y
.
Proposition:
If X
is an includer
then X
s means the set of objects that
are kind of X
.
This convention is usually applied to named classes or modules.
Notes:
kindin the phrase
(l) is kind of (r)construes with the right side of the phrase, so that we cannot express
X
s as kindsof
X
.
X
is a class then X
s means instances of X
.
kind of BasicObject 
Pure instances
(nonincluders) 

kind of Object 

kind of Module 
Modules 

kind of Class 
Classes and Eigenclasses 
Module
subtable provides the following nomenclature of includers:
Classes  ⊂  Class es 
⊂  Module s 
⊃  Modules 
∥  ∥  ∥  ∥  
Class es − Eigenclasses 
Nonterminals  Includers  Module s − Class es 
Module
.
(Classes ⊂ Module
s.)
Class
.
(Modules ∩ Class
es == ∅.)
Note: Another diagram of the nomenclature is provided as a side view of an example of the S2 structure. This diagram is a refinement of the 2x2 nomenclature table.
Object
s
Object
are considered
blank slate objects.
BasicObject
s
== Object
s ⊎ (blank slate objects).
Note: (∗) Each of the 5 division lines partitions the set of objects into two complementary subsets, specified as <set> / <complemetary set>.
The structure can be created as follows.class S < String; end; class A; end; class B < A; end; class X < Module; end module R; end; module M; end; N = X.new s = S.new; i = 20; j = 30; k = 2**70; b = B.new class BasicObject; include ::R end class B; include M end class << B; include M end class X; include M end class << X; include M end module N; include M, Comparable end class << s; include N endThe code first builds classes (
S
, A
, B
, X
),
then modules (R
, M
, N
),
then nonincluders
(pure instances
s
, i
, j
, k
, b
).
Finally, inclusion lists are created.
The diagram shows that inclusion lists refine the sc
inheritance.
This refined structure is refered to as
MRO in the next section.
Ancestor lists in the structure
can be reported (without eigenclasses) by the following code
().
class Object; def ec; singleton_class rescue self.class end end %w{s i j k b }.each { x puts "%s.ec: %s" % [x, eval(x).ec.ancestors] } %w{B.ec X.ec N X}.each { x puts "%s: %s" % [x, eval(x).ancestors] }
Notes about
R
into BasicObject
.
R
(more precisely, the pair (BasicObject, R)
)
is the root in the example's MRO structure.
BasicObject
are untypical.
Our inclusion has been made to show that
BasicObject
is not necessarily the MRO root.
R
can be superceded by a new root after e.g.
module R; include (R = Module.new) end class BasicObject; include ::R end p Object.ancestors #> [Object, Kernel, BasicObject, R, R::R]
Μ
.
The domain Μ
consists of the following two disjoint sets of elements:
(x,x)
with x
being an includer
(includer elements).
(x,y)
with y
being a member of x.incs
(iclass elements,
y
is necessarily a module).
inclusion class.
.super
.super
defined on the MRO domain Μ
as follows:
(x,x)
,
(x,x).super == (x.incs[0], x)
if x.incs
is nonempty, else
(x,x).super == (x.sc, x.sc)
if x.sc
is defined, else
(x,x).super
is undefined.
(x,y)
with x
different from y
,
(x,y).super == (x, x.incs[i+1])
if
y
equals x.incs[i]
for some
i < x.incs.length1
, else
(x,y).super == (x.sc, x.sc)
if x.sc
is defined, else
(x,y).super
is undefined.
(x,y).super(i)
the i
th application of
.super
to (x,y)
.
(Μ, ≤)
is defined by
(x,y) ≤ (a,b) iff


Proposition:
(x,y) ≤ (a,b)
iff
(x,y).super(i)
equals (a,b)
for some i
,
i.e.
(Μ, ≤)
is a reflexive transitive closure of
(Μ, .super)
.
(r,r)
,
called the MRO tree.
Its root equals either (r,r)
or
(r, r.incs.last)
.
.ancs
the function from the set
of includers to the set of lists of includers defined by
x.ancs[i] == y
iff (x,x).super(i) == (w,y)
for some
w
.
x.ancs[i]
is defined then it is said to be the i
th
(MRO) ancestor of x
.
The Ruby .ancestors
builtin method filters out eigenclasses:
For each class or module x
,
x.ancestors
equals x.ancs
without eigenclasses.
Proposition:
Let x
, y
be includers.
x ≤ y
iff x.ancs
contains y
.
x.ancs == [x] + x.incs + x.sc.ancs
if x.sc
is defined,
x.ancs == [x] + x.incs
otherwise
(i.e. if x
is a module or equals r
).
(x,y)
is in Μ
iff
y
is in x.ancs
and only modules appear before the first occurrence of
y
in x.ancs
.
(x,y)
is in ℍ
iff
y
is in x.ancs
and is not a module.
x
, the inheritance ancestor list x.hancs
is obtained from x.ancs
by removing modules.
x
is not an eigenclass then x.ancs
does not
contain an eigenclass (i.e. x.ancs == x.ancestors
).
(.sc, .incs)
replaced by (.ancs, .module?)
where .module?
is a boolean attribute indicating whether an object is a module.
(Μ, ≤)
reflects the fact that the relation is used in Ruby's method resolution.
However, only the MRO tree is used in this respect.
On the other hand, qualified constant resolution uses all components
of (Μ, ≤)
so that
the term qualified constant resolution order / QCROwould be more appropriate. The reason we have chosen MRO is because this term has already been established in the Python programming language [] [].
The following rules apply:
State transitions S → S' are substructural in the S2 structure.

Proposition:
x ≤ y
in S
then
x ≤ y
in S'
.
S
are not necessarily restrictions of their counterparts in S'
.
In particular, for an includer x
,
(x,x).super
can differ between S
and S'
.
(Note that it is in contrast to the superclass (partial) function .sc
.)
S → S'
with two parameters:
p
.
q
.
acceptediff the following holds:
q
is a module
– otherwise an error wrong argument type
is raised.
p
does not occur in [q] + q.incs
(== q.ancs
)
– otherwise an error cyclic include detected
is raised.
S'
equals S
(possibly) except for the
inclusion list p.incs'
which is defined as follows.
Denote A = p.incs & ([q] + q.incs)
so that A = [a_{1}, …, a_{n}]
is the (possibly empty) list of
common elements of p.incs
and [q] + q.incs
, ordered
according to p.incs
.
Then the p.incs'
list is defined as
the concatenation of lists l_{0}, …, l_{n}
where
l_{0} = (s_{0}  p.ancs) + t_{0}
where s_{0}
and t_{0}
are maximum prefixes (initial sublists)
of [q] + q.incs
and p.incs
, respectively,
that are disjoint from A
.
l_{i} = [a_{i}] + (s_{i}  p.ancs) + t_{i}
,
i = 1, …, n
,
where [a_{i}] + s_{i}
and [a_{i}] + t_{i}
are maximum slices (interval sublists)
of [q] + q.incs
and p.incs
, respectively,
that are disjoint from A  [a_{i}]
.
s_{i}
,
without any modules that appear along the p.ancs
ancestor chain
(note that this can only happen if
p
is a class or eigenclass,
for modules p
the subtractionis already made by excluding elements from
A
)
are
prepended before the start for i == 0
and
inserted after a_{i}
for 1 ≤ i ≤ n
.
In most cases, A
is empty, so that
p.incs' == [q] + (q.incs  p.ancs) + p.incs
,
q
's inclusion list,
without the modules already appearing in p.ancestors
,
is prepended to p
's inclusion list.
Subsequently, the single element list [q]
is prepended.
T0, T1, T2, S0, S1, S2, A1, A2 = Array.new(8).map { Module.new } module P; include T0, A1, T1, A2, T2 end module Q; include S0, A2, S2, A1, S1 end module P; include Q end p P.included_modules #> [Q, S0, T0, A1, S1, T1, A2, S2, T2]
include
method of Module
,
e.g.
class X; include M end
The extend
method of Kernel
provides a shorthand for inclusion into eigenclasses:
x.extend(M)
is roughly equivalent to
class << x; include M end
include
and extend
might be considered
outer
methods of the
form
<outermethod> ==
<innermethod> + <hookmethod>
hooks:
0 
1 



Outer method  include 
extend 

Inner method  append_features 
extend_object 

Hook  included 
extended 
module M; end class << M def append_features(x); puts "inner: #{self} as includee of #{x}"; super end def included(x); puts "hook: #{self} as includee of #{x}" end def extend_object(x); puts "inner: #{self} as extender of #{x}"; super end def extended(x); puts "hook: #{self} as extender of #{x}" end end class X; end x = X.new class << x; include M end # inner: M as includee # hook: M as includee x.extend(M) # inner: M as extender # hook: M as extender
Notes:
coincideswith the inclusion list order [].
sc
inheritance ancestor lists).
Examples:
module A; end; module B; end; module C; end  
↙  ↘ 
module A; include B end module B; include C end 
module B; include C end module A; include B end 
↘  ↙ 
p A.included_modules  
#=> [B] 
#=> [B,C] 
(A,B,C)
is created.
(The redframed case of the previous example.)
module A; end; module B; end; module C; end module A; include B end module B; include C end puts "%p, %p, %p" % [A < B, B < C, A < C] #=> true, true, nil
module L; end module M; include L end module A; end module L; include A end # M does not know about this module A; include M end # inclusion cycle A < M < L < A created puts "#{A.include? L}, #{L.include? A}" #=> true, true puts "#{A < L}, #{L < A}" #=> true, true
module M; end class X; end class Y < X; include M end class X; include M end p Y.ancestors # [Y, M, X, M, Object, Kernel, BasicObject]
(O, Φ, Φ_{A},
FALSE, TRUE, NULL, UNDEF, ℤ, ℱ, ℬ, .φvalue)
where
O
is the already introduced set of objects.
Φ
is a value domain,
disjoint from the set O
of objects.
Φ_{A}
is a subset of Φ
,
elements of Φ_{A}
are called atomic.
FALSE
and TRUE
are distinct elements of Φ_{A}
,
having the semantics of boolean values.
NULL
and UNDEF
are distinct elements of Φ_{A}
,
indicating undefinedness.
ℤ
is a subset of Φ_{A}
representing the set of integer numbers.
ℱ
is a subset of Φ_{A}
(disjoint from ℤ
)
representing the set of floating point numbers.
ℬ
is a subset of Φ_{A}
.
It is a set of bytestrings
which are finite sequences of bytes.
A byte can be considered a copy of an integer within the 8bit range 0, …, 255.
Bytes corresponding to the 7bit range of 0, …, 127 are called ascii.
(ℬ, +, '')
where
+
is bytestring concatenation,
''
is the empty bytestring.
.φvalue
is a partial function from O
to Φ
assigning objects their
semantic value.
x
for which x.φvalue
is defined
are called φvalue
d.
Note:
Gray color indicates that merging V1 and S2 structures yields
a single meaning for the O
symbol.
The following condition is required:
(V1~1) 
Tuples of atomic elements belong to the value domain,
i.e. all finite products
Φ_{A} × Φ_{A} × ⋯ × Φ_{A}
are subsets of Φ .

Note:
φvalue
d:
Symbol
s and String
s are
φvalue
d by pairs from ℬ × ℬ
(via estrings).
Rational
s are
φvalue
d by pairs from ℤ × ℤ
.
(FalseClass, TrueClass, NilClass, false, true, nil)
where
Object
.
(Fixnum, Integer, Numeric)
where
Fixnum
, Integer
and Numeric
are classes such that
Fixnum < Integer < Numeric < Object
is a direct inheritance chain.
Fixnum
are caled fixnums.
(Symbol, Υ)
where
Symbol
is a class, a direct descendant of Object
.
Υ
denotes the set of Symbol
instances (Symbol
s).
Υ
are called symbols.
false
, true
, and nil
together with fixnums and symbols are called immediate values.
The structure is subject to the following axioms:
(S3~1) 
Immediate values are φvalue d according to the following table:
 
(S3~2) 
The restriction of
.φvalue to the set of all immediate values is injective.
 
(S3~3) 
The terminals false , true , and nil
are the only instances of their respective classes.
 
(S3~4)  Classes of immediate values are quasifinal. 
Notes:
φvalue
s.
.φvalue is preserved on immediate values.

(.actual?)
where
.actual?
is a boolean attribute of objects.
.actual?
set to true are actual(s),
otherwise are nonactual(s).
We also provide a setalternative for .actual?
by denoting O_{a}
the set of all actual objects.
The structure is subject to the following axioms:
(S4~1)  Only finitely many objects can be actual. 
(S4~2)  Only eigenclasses can be nonactual. 
(S4~3) 
.ce preserves actuals.
For every eigenclass x ,
if x is actual then x.ce is actual.

(S4~4) 
.sc preserves actuals.
For every eigenclass x ,
if x is actual then x.sc is actual.

If r.ec(i) is actual then so is r.class.ec(i) .
 
r.class.ec ,
the Class 's eigenclass, is actual.
 
(S4~7)  Only actuals can be included or have includees. 
(S4~8)  Eigenclasses of immediate values are nonactual. 
O_{a} ⊆ O_{₀₁}
, i.e. if
only primary objects and (some) first eigenclasses are actual
(equivalently, eigenclasses of eigenclasses are not actual),
O_{a}
equals the set
(primary objects) ⊎ ((first) eigenclasses of classes).
Note that this a special case of conventional actuality.
O_{a}
== (primary objects) ⊎ ((first) helix eigenclasses).
x
, we denote x.actuals
the list corresponding to the finite .ec
subchain of actual objects
starting at x
.
Note that under conventional actuality, x.actuals.length ≤ 2
for every primary object x
.
Helix actual lists are equally sized.  
Eigenclasses of helix classes are actual. 
Proposition:
r.class.actuals.last
is the least actual helix object in the inheritance.
r.actuals.length == 2
).
.aclass
function maps objects to actual nonterminals
(classes or actual eigenclasses).
For every object x
,
it is defined recursively by
x.aclass == x.ec
if x.ec
is actual, else
x.aclass == x.ec.sc
(== x.class
)
if x
is terminal, else
x.aclass == x.sc.aclass
.
x.aclass
the actualclass of x
.
Proposition:
x
,
x.aclass
equals the first actual member of x.ec.hancs
,
x.class
==)
x.ec.hancestors[0] == x.aclass.hancestors[0]
.
.aclass
map forms
an algebraic tree – the actualclass tree.
r.class.actuals.last
.
Class.ec
.
r.actuals.length + 1
(3 under conventional actuality).
Example:
Assume conventional actuality and let
A
be a direct subclass of Object
and
a
a direct instance of A
.
Then there are four possible .aclass
chains from a
to Class.ec
according to whether a.ec
and A.ec
are actual or not.
a 
→  A 
→  Object.ec 
→  Class.ec 

a 
→  A 
→  A.ec 
→  Class.ec 

a 
→  a.ec 
→  A.ec 
→  Class.ec 

a 
→  a.ec 
→  Object.ec 
→  Class.ec 
.ec ≤ .aclass ≤ .class
refinement
.aclass
, can be considered a refinement
of the class map, .class
.
Further observation shows that .aclass
can be considered a coarsement of the eigenclass map, .ec
,
so that we have the following refinement chain:
.ec ≤ .aclass ≤ .class
.
≤
restricted to nonterminals
equals the inheritance ℍ
which is an algebraic tree.)
Proposition:
x
,
x.ec ≤ x.aclass ≤ x.class
.
.ec
, .aclass
and .class
form a chain when ordered pointwise by the HM descendancy.)
x
,
x.ec 
is the first member of x.ec.hancs , 

x.aclass 
is the first member of x.ec.hancs 
that is actual, 
x.class 
is the first member of x.ec.hancs 
that is a class. 
Note:
Gray color indicates that statements are valid for both
.hancs
and .ancs
.
.f
of the .ec
, .aclass
or .class
maps
is monotone with respect to the inheritance ℍ
, i.e.
for every nonterminals x
, y
,
x ≤ y
implies
x.f ≤ y.f
.
x
and every i > 0
,
x.ec(i) ≤ x.aclass(i) ≤ x.class(i)
.
.aclass
map is related
to MRI 1.9 implementation,
we introduce
a function .saec
,
meaning semiactual eigenclass,
partially defined for primary objects as follows:
x.saec
is defined iff x
is
x.actuals.length > 2
.
x.saec
is defined then it equals x.actuals.last.ec
.
.saec
are called semiactual(s).
Thus, semiactuals are (right) covers of actual lists
except for 12 sized actual lists starting with terminals
– such lists are uncovered.
We also introduce a 3valued attribute of .actuality
which is defined on all objects according to the table below.
Object set  x.actuality 

nonactuals  0 

semiactuals  1 

actuals  2 
For every terminative eigenclass x ,
if x is actual or semiactual then
x.sc.ec is actual or semiactual.

.klass
map
.klass
map provides a
virtual connectionto object's eigenclass. We consider two versions:
.klass
is a partial map between actual objects.
For every actual object x
,
x.klass == x.ec
if x.ec
is actual, else
x.klass == x.ec.sc
(== x.class
)
if x
is terminal, else
x.klass
is undefined.
.klass
is a map between actual or semiactual objects
defined according to the MRI 1.9 implementation.
For every actual or semiactual object x
,
x.klass == x.ec
if x.ec
is actual or semiactual, else
x.klass == x.ec.sc
(== x.class
)
if x
is terminal, else
x.klass == x.sc.ec
if x.pr
is terminal
and x
is actual or semiactual, else
x.klass == c.ec(x.eci)
(if x.pr
is a class and x
semiactual
– the value is probably unimportant).
Proposition:
.klass
map
is a restriction of both
the .aclass
and the full version of .klass
.
.klass
is a generator of .aclass
in the following sense: For every actual x
,
x.aclass == x.klass
if x.ec
is actual or x
terminal,
x.aclass == x.sc.aclass
otherwise.
State transitions S → S'
are incremental in the S4 structure in the following sense.
For every object x from
O ∩ O' ,

S → S'
with a single parameter
x
 an actual object whose eigenclass x.ec
is requested to be made actual.
S'
equals S
(possibly) except for the
set of actual objects.
The difference between sets of actual objects, denoted x.acdelta
,
is defined as follows
(all functions are taken in S
).
x.acdelta == []
if x.ec
is actual, else
x.acdelta == [x.ec]
if x
is terminal, else
x.acdelta == [x.ec] + x.sc.acdelta
if x.pr
is a nonhelix
class, else
x.acdelta == r.class.hancs.map{c c.ec(x.eci+1)}
if x.pr
is a helix class, else
x.acdelta == [x.ec] + x.sc.ec.acdelta
if
(x.pr
is terminal and) x.eci != 1
, else
x.acdelta == [x.ec] + x.sc.acdelta + x.sc.ec.acdelta
(if x
is the eigenclass of a terminal).
Note:
The recursive definition in (5) and (6) requires that
x.acdelta
is defined also for nonactuals.
x.acdelta == [x.ec] + x.sc.acdelta
(if x.pr
is terminal)
– the same prescription as in (3) applies.
Proposition:
In case (B), x.acdelta
, as a set,
equals the union of the following (possibly empty) sets Δ1 and Δ2
(all functions are taken in S
):
x.ec.hancs  x.aclass.hancs
.
r.class.actuals.last.ec.hancs  y.hancs
if y
is the .sc
least helix object of Δ1, or
x.aclass
and then equalize helix actual lists.
The following examples of Ruby code show several ways of x
's eigenclass
actualization.
x.ec
.
class << x; end
x.singleton_class
x.ec
's inclusion list (or attempting extension).
x.extend(Module.new)
x.extend(Kernel)
(including an already included module)
x.ec
's own method
(aka singleton method of x
)
def x.dummy; end
x.instance_eval { def dummy; end }
x.define_singleton_method("", lambda{})
x.module_function(:m)
(if x
is a module having own method m
)
Notes:
can't define singleton
is raised).
Numeric
s
that are not Fixnum
s
(an error can't define singleton method
is raised).
T_CLASS
counter
ObjectSpace.count_objects[:T_CLASS]
counts the following objects in total:
module Kernel def nnt_delta # number of nonterminals delta @nnt = 0 nnt = ObjectSpace.count_objects[:T_CLASS] delta = nnt  @nnt @nnt = nnt delta end def nnt_delta_report; puts "nnt_delta: #{nnt_delta}" end end
nnt_delta_report # nnt_delta: 387 class X; end nnt_delta_report # nnt_delta: 2
Proposition:
Assuming x
which is not an
immediate value, x.acdelta.length
equals
nnt_delta  1
if x.eci == 1
,
x.pr
is terminal and x.pr.actuals.length == 2
,
nnt_delta
otherwise.
(.cparent, .cname)
where
.cparent
is a partial function between includers,
.cname
is a partial function from includers to symbols.
.cparent
is called
includer containment or just containment
and denoted Ϲ
.
x.cparent
, if defined, is called
the containment parent of x
.
x.cname
, if defined, is called
the (containment) name of x
.
x.cparent(i)
denotes the i
th application
of .cparent
to x
.
(S5~1) 
The containment Ϲ is an algebraic forest
(with .cparent undefined on roots).

(S5~2) 
There is exactly one containment root x such that x.cname
is defined, namely the Object class.

(S5~3) 
If x.cparent is defined then
x.cname is defined.
(Nonroots are named.)

(S5~4) 
For every eigenclass x , x.cname is undefined.
(Eigenclasses are anonymous, therefore roots.)

(S5~5)  Anonymous classes and modules have no containment descendants. (Thus, being roots, they are containment singletons.) 
(S5~6)  Nonactuals have no containment descendants. (Thus, being roots, they are containment singletons.) 
(S5~7) 
Containment names are constant names.
(This statement comes into effect as soon as the meaning of being a constant nameis defined.) 
(S5~8) 
If x.cparent is Object then
x.cname differs from Object.cname .

Proposition: Components of the containment forest are trees of the following 3 types:
maintree rooted at
Object
.
Note:
offshoots.
offshootsare chains corresponding to moduleinmodule inclusion lists.
offshoots, if any, are usually of minor importance.
x.cancs
the list of containment ancestors of x
,
i.e.
x.cancs
is defined iff x
is an includer,
x.cancs[i] == y
iff x.cparent(i) == y
.
x.croot
the containment root of x
,
x.croot == x.cancs.last
,
x.cpathname
the (proper) containment pathname of x
defined by
x.cpathname == (x.cancs  [x.croot]).reverse.map{y y.cname}.join("::")
,
::
".
Note that for every containment root x
(in particular, Object
),
x.cpathname
is an empty string.
State transitions S → S'
preserve x.cparent
and x.cname
whenever x.cparent is defined.

S → S'
with three parameters:
p
which is an actual includer.
n
.
q
which is an anonymous class or module
to be named by n
.
requestsfor containment binding.
p
being a named class or module.
p
being an anonymous class or module.
p
being an eigenclass.
Group  Container p 
Name n 
Ruby code  Containee q (after transition) 

q.croot 
q.cpathname 

A  Object 
"Q" 
class Q; end 
Object 
Q 

X 
class X; class Q; end end 
Object 
X::Q 

X 
X::Q = Class.new 
Object 
X::Q 

C1  X.ec 
class << X; class Q; end end 
X.ec 
Q 

q = Class.new 

C2  X.ec 
X.singleton_class::Q = q 

B  x 
x::Q = q 

x 
x.class_eval { self::Q = q } 
Notation / Expression  Terminology / Description  Domain  Generating map  Relation characteristics 
ℍ
(Class es, ≤) 
inheritance  nonterminals  .sc 
algebraic tree 
ℙ 
primorder  all objects  .ec 
componentwise isomorphic to the linear order of natural numbers 
ℍ ↾ (classes) 
selforsubclassof  classes  .sc ↾ (classes) 
finite algebraic tree 
Μ 
selforownincluderof  includers  —  reflexive and antisymmetric 
≤
(ℍ ◦ Μ) ∪ Μ 
HM descendancy  includers  —  reflexive 
(Μ, ≤) 
MRO  Μ 
.super 
algebraic forest 
instance tree  all objects  .class (aka directinstanceof) 
algebraic tree of depth 2  
.class ◦ ℍ 
instanceof  all objects  —  complete (anytoany) on helix classes, irreflexive and antisymmetric otherwise 
.ec ◦ ≤ 
kindof  all objects  —  
actualclass tree  all objects  .aclass 
algebraic tree (of depth 3 under conventional actuality)  
Ϲ 
includer containment  includers  .cparent 
algebraic forest 
(.frozen?, .tainted?, .trusted?)
where
.frozen?
, .tainted?
and .trusted?
are boolean attributes of objects.
(S6~1) 
If x is frozen then x.ec is frozen.

(S6~2) 
If x is tainted then x.pr is tainted.
(.ec chains are tainted as a whole.)

(S6~3) 
If x is trusted then x.pr is trusted.
(.ec chains are trusted as a whole.)

(S6~4)  Immediate values are trusted. 
Transitions S → S'
preserve being frozen, i.e. if x is frozen in S
then it is so in S' .
 
Inclusion lists of frozen includers cannot be extended.  
Transitions preserve taintedness of frozen objects.  
Transitions preserve trust of frozen objects.  
Transitions preserve .φvalue of frozen objects.

freeze
and taint
/untaint
methods, respectively.
(nestlists, selfs)
where
nestlists
is a nonempty finite list of (possibly empty) finite lists
of actual includers,
selfs
is a nonempty finite list of actual objects.
nestlists.last.reverse
is denoted nesting
and called the current nesting.
selfs.last
is denoted self
and called the current object.
selfs[0]
is denoted main
and called the main context.
(S7~1) 
Classes and modules that appear in nesting are named.

(S7~2) 
main is a direct instance of Object .

nesting[0]
exists and is a class or module,
then
nesting[0].cancs
equals nesting
.
pseudorulebecause it only reflects a common pattern of a nested class/module definition, e.g.
class A class B class C # current nesting corresponds to A::B::C end end endWriting
class ::C
instead of class C
would break
the pseudorule.
The main context main
remains unchanged across transitions.

nesting
gets changed:
explicit and implicit.
An explicit change is performed via class/module/eigenclass (re)definition.
In this case,
nesting
changes correspond to
prepending/removing one object to/from the front of nesting
,
i.e. they are equivalent to
nesting.unshift(y)
and nesting.shift
,
respectively.
The unshift operation is includer opening
and can have one of the following forms:
class X
for a class X
,
module M
for a module M
,
class << x
for an eigenclass x.ec
.
end
.
nesting
change is obtained via method invocation
as demonstrated by the following code:
class X class Y; def self.nest1; Module.nesting end end # defnesting is [X::Y, X] def Y .nest2; Module.nesting end # defnesting is [X] end class A p Module.nesting # [A] p X::Y.nest1 # [X::Y, X] p X::Y.nest2 # [X] endThe example shows that each method has its own nesting which becomes the current nesting after method invocation. The method's nesting equals the current nesting at the time of method definition.
(Ω, ω(), OID, .oid, IVN, .invals)
where
Ω
is a finite set of object datarepresentatives,
which we also call ω
objects.
Ω
is disjoint from O
.
ω()
is a partial injective map
from O × O
onto Ω
.
OID
is an objectidentifier domain, a subset of integers.
.oid
is an injective map from Ω
to
OID
.
IVN
is a finite set of internal value names,
a subset of the value domain Φ
.
.invals
is a function from nonincluders to
the set
IVN ↷ Φ
of partial maps from internal value names to the value domain Φ
.
(S8~1) 
ω(a,b) is defined iff the following are satisfied:

ω(a,b)
with a
different from b
iclasses (inclusionclasses).
Condition (S8~1) says that
Ω
is a copy of
all actual MRO domain pairs extended by all pairs (x,x)
with
x
being a pure instance (nonincluder).
Equivalently,
Ω
is a copy of the set of all actual objects extended by the set of iclasses.
This is illustrated by the following diagram.
Extended actual O 
Data representatives  Extended actual Μ 

iclasses 
actual MRO pairs  
actual objects  actual includer representatives 

nonincluder representatives 
Ω
:
ω(x,y).module ≝ ω(x,x)
whenever ω(x,y)
is an iclass.
ω(x,y).super ≝ ω((x,y).super)
whenever (x,y).super
(the MRO parent of (x,y)
) is defined.
ω(x,x).func ≝ ω(x.func, x.func)
whenever .func
is a (partial) function on O
and x.func
is defined.
ω(x,x).func ≝ x.func
whenever .func
is a (partial) function from O
to Φ
and x.func
is defined.
ω
objects are identifiable with
OID
s
we can regard functions defined on Ω
as data fields.
The following table presents a distinguished datafield subset.
Field Name 
Domain (Type) 
Applicability  Description  Relevant field(s) in Ruby implementation 

nonincluder  includer  iclass  
oid 
OID  ●  ●  ●  ω object id 

super 
OID  ●  ●  MRO parent  super 

ce 
OID  ●  eigenclass predecessor  __attached__ 

klass 
OID  ●  ●  actualclass generator  klass 

module 
OID  ●  iclass originator  
cparent 
OID  ●  containment parent  __classid__ and/or__classpath__ 

cname 
string 
●  containment name  
frozen? 
boolean  ●  ●  frozenness  part of flags 

tainted? 
boolean  ●  ●  taintedness  
trusted? 
boolean  ●  ●  trust  
type 
ENUM_T  ●  ●  ●  basic type  
invals 
IVN ↷ Φ 
●  internal value(s) 
Notes:
oid
indicates a primary key.
cparent
in Ruby's implementation.
stringindicate that the domain of of
cname
s should be more precisely described
as φvalue
s of Symbol
s.
The type
field indicates the basic type with the following enumeration
domain
(we assume that ENUM_T is a subset of Φ
):
Value  Meaning of ω(x,y) 
T_ICLASS 
iclass 
T_CLASS 
class or eigenclass 
T_MODULE 
module 
T_NONINC 
nonincluder (pure instance) 
ωobjects
data table
ωobjects
data table, with onetoone correspondence between
rows and object datarepresentatives.
oid 
super 
ce 
klass 
module 
cparent 
cname 
frozen? 
tainted? 
trusted? 
type 
invals 

…  
Proposition:
The ωobjects
data table
uniquely determines the S6 structure,
up to isomorphism and except for the .φvalue
function.
Prefix  Notation  Terminology  Description 
class  A primary nonterminal object.  
e  eigenclass  A secondary object.  
metaclass  A (nonstrict) inheritance descendant of the Class class. 

explicit metaclass  A metaclass that is a class.
In Ruby, the Class class is the only explicit
metaclass.
The set of explicit metaclasses equals the set of classes of classes.


implicit metaclass 
A metaclasss that is an eigenclass.
The set of implicit metaclasses equals the set of eigenclasses of Class es.


e 
.ec 
the eigenclass map  A map from objects to eigenclasses. 
s 
.sc 
the superclass map  A partial map between nonterminal objects. 

.class 
the class map  A map from objects to classes.
The second application, .class(2) , is constant. 
directsubclassof  A relation which equals the restriction of .sc to classes. 

subclassof  The transitive closure of directsubclassof.  
directsuperclassof, superclassof  Inverses of directsubclassof and subclassof, respectively. Not used in this document to avoid terminological conflicts with the superclass map.  
directinstanceof  Equivalent to .class
(i.e. x directinstanceof y
iff x.class == y ). 

instanceof  Composition of directinstanceof and selforsubclassof.  
classof  Inverse of directinstanceof.  
Class 
(A) the Class class 
The instance tree root, and, simultaneously, the metaclass tree root.
Denoted c , equal to r.class . 

(B) a Class 
A class or an eigenclass.
An instance of the Class class.
An object that is kindof Class .


Class es 
Class instances 
Classes and eigenclasses.  
helix classes  Classes that belong to the Ruby helix.
Members of
c.hancs , i.e.
Class , Module , Object , and BasicObject .


a 
.aclass 
the actualclass map  A map from objects to actual eigenclasses or classes.
The n th application, .aclass(n) , is constant,
where n equals r.actuals.length + 1
(n == 3 under conventional actuality).

i  iclass  An inclusion class, abstraction of an includerincludee pair. 


.klass 
the actualclass generator 

singleton class  Equivalent to eigenclass.
Not used in this document to avoid a conflict with the term class.
Note:
The word 
(Encoding, ℇ, ℇ_{¢}, ℇ_{$}, .name, e8b, e7b,
⅀, ⅀_{⋄}, ≘)
where
Encoding
is a class, a direct descendant of Object
.
ℇ
denotes the set of Encoding
s, called just encodings.
ℇ_{¢}
is a subset of ℇ
,
containing encodings with proper character handling support.
ℇ_{$}
is a subset of ℇ_{¢}
,
containing asciicompatible encodings.
.name
is an injective function from Encoding
s to
ascii bytestrings.
(Even .name.upcase
is injective.)
e8b
is a distinguished asciicompatible encoding,
called binary and name
d 'ASCII8BIT'
.
e7b
is a distinguished asciicompatible encoding,
called ascii and name
d 'USASCII'
.
⅀
denotes the set ℬ × ℇ
– the set of pairs (s,e)
where
s
is a bytestring and
e
an encoding.
Elemens of ⅀
are called estrings,
meaning encoded strings.
⅀_{⋄}
is a subset of ⅀
, containing
valid estrings.
≘
is an equivalence relation on the set ⅀_{⋄}
of valid estrings.
{e8b, e7b} ⊆ ℇ_{$} ⊆ ℇ_{¢} ⊆ ℇ
.
The structure is subject to the following axioms:
(D0~1) 
('',e) is a valid estring for every encoding e .

(D0~2) 
(s,e8b) is a valid estring for every bytestring s .

(D0~3) 
(s,e7b) is a valid estring iff
s is an ascii bytestring.

(D0~4) 
(s,e7b) ≘ (s,e8b) whenever
(s,e7b) is a valid estring.

(D0~5) 
(s,e) ≘ (t,e) implies s == t ,
i.e. valid ≘ equivalent estrings with the same encoding are equal.

(D0~6) 
For every asciicompatible encoding e and
every valid estring (s,e7b) ,
(t,e) .

(D0~7) 
For every encoding e from ℇ_{¢} and every
bytestrings s , t such that (s,e) is valid,

(D0~8) 
If a , b are leading characters
^{∗}
of x , y , then

(∗)
For a valid estring x = (s,e)
with nonempty bytestring s
and encoding e
from ℇ_{¢}
,
we denote x.chr
the leading character of x
defined as the unique valid atomic prefix of x
, i.e. it is a
valid estring (u,e)
such that
u
is nonempty,
u + v = s
for some bytestring v
,
u
is the smallest bytestring satisfying the previous condition.
Set membership  Ruby booleanattribute reflection  
Expression  Terminology / description  
x ∈ ℇ_{¢} 
encoding x supports proper character handling 
!x.dummy? 
x ∈ ℇ_{$} 
encoding x is asciicompatible 
x.ascii_compatible? 
x ∈ ⅀_{⋄} 
estring x is valid 
x.valid_encoding? 
estring x is
asciionly

x.ascii_only? 
⅀_{¢}
the set of all valid estrings with encoding from
ℇ_{¢}
. We call such estrings chardecomposable.
⅀_{e}
the set of all valid estrings with encoding e
.
.encode()
map
.encode()
function maps valid estrings to their
≘
equivalents in given encodings,
i.e. it is a partial function from ⅀_{⋄} × ℇ
to
⅀_{⋄}
such that
(s,e).encode(f) == (t,f)
iff
there is a bytestring t
such that (s,e) ≘ (t,f)
.
Proposition:
(s,e)
and every encoding f
,
(s,e).encode(f).encode(e) == (s,e)
(s,e).encode(f)
is defined.
x
are called
x.encode(e7b)
is defined,
e7b
encoding,
equivalenty x == x.encode(e7b)
.
x
and an ascii bytestring s
, we might write
x == s
for x == (s,e7b)
.
(This is later applied, for instance, for x == 'method_missing'
.)
∔
is a partial binary operator
on the set ⅀_{¢}
of chardecomposable estrings defined by
(s,e) ∔ (t,f) == (s + t, e)
if e == f
,
(s,e) ∔ (t,f)
is undefined, otherwise.
.chars
is a function from ⅀_{¢}
to finite lists over ⅀_{¢}
defined recursively by
(s,e).chars == []
if s
is empty, else
(s,e).chars == [(u,e)] + (v,e).chars
where
u
, v
are the unique bytestrings such that u + v == s
and u
is the smallest nonempty such that (u,e)
is valid
((u,e)
is the leading character of (s,e)
).
s
from ⅀_{¢}
,
s.length
is the length of s.chars
,
s[i]
denotes the i
th member of s.chars
.
Proposition:
(⅀_{e}, ∔, ('',e))
is
a free monoid for every encoding e
from ℇ_{¢}
.
s == s[0] ∔ s[1] ∔ ⋯ ∔ s[n1]
for every chardecomposable estring s
of length n
.
e
, f
from ℇ_{¢}
,
.encode(f)
is an isomorphism between
(⅀_{e}, ∔, ('',e))
and
(⅀_{f}, ∔, ('',f))
.
.encode(f)
and .chars
commute,
.encode(f)
preserves .length
.
+
on valid estrings
satisfying the following:
x + y == x ∔ y
whenever x ∔ y
is defined,
('',e) + x ≘ x ≘ x + ('',e)
,
(s,e) + x ≘ (s,e) ∔ x.encode(e)
whenever x
is asciionly, similarly
x + (s,e) ≘ x.encode(e) ∔ (s,e)
whenever x
is asciionly.
x
can startwith an ascii estring even if
x
is not ascii.
For transitions S → S' ,
all of the following are fixed for encodings and estrings
existing both in S and S' :
the ℇ_{¢}  and ℇ_{$}  set memberships,
validity of estrings, the ≘ equivalence.
 
Encoding name s are preserved across transitions.

(String, .estr)
where
String
is a class, a direct descendant of Object
.
.estr
is a function from
String
s and Symbol
s to the set ⅀
of estrings.
(D1~1) 
String s and Symbol s are φvalue d by
pairs of bytestrings as follows:
(s,e) == x.estr .

(D1~2) 
For every symbol x ,
the estring x.estr is valid.

(D1~3) 
For every symbol x ,
if x.estr ≘ (s,e7b) for some s then
x.estr == (s,e7b) .
(I.e. asciionly symbols are ascii.) 
Notes:
String
s.
Proposition: The following are consequences of the already introduced conditions:
.estr
is preserved on symbols.
.estr
is preserved on frozen strings.
(Array, ._list)
where
Array
is a class, a direct descendant of Object
.
._list
is a function
from the set of all Array
s to finite lists of objects.
Array
s are called arrays.
Notes:
0, …, n1
for some natural n
.
a
be an array and i
an integer. Then
a.length
denotes the cardinality of (the domain of) a._list
.
a[i]
is defined as follows:
a[i] == a._list(i) 
if 0 ≤ i < a.length , 
a[i] == a._list(a.length  i) 
if a.length ≤ i < 0 , 
a[i] == nil 
otherwise. 
Transitions S → S'
preserve ._list on frozen arrays,
i.e. if a is a frozen array,
then a[i] equals a[i]'
and a.length equals a.length' .

(Hash, .hcodes, .keys, .values,
.compare_by_identity?, .dflt, .dflt_call?, Proc)
where
Hash
and Proc
are classes,
direct descendants of Object
.
Hash
es are called hashes.
The remaining members are functions on the set of all hashes.
For every hash x
,
x.hcodes
is a finite list of integers called hash codes.
x.keys
is a finite list of objects called keys.
x.values
is a finite list of objects called values.
x.compare_by_identity?
is a boolean attribute.
x.dflt
is an object determining the default value.
x.dflt_call?
is a boolean attribute determining
whether x.dflt
is interpreted indirectly
– as the default's value evaluator,
or if it is interpreted directly as the default value itself.
x
is subject to the following conditions:
(D3~1) 
The list x.hcodes.zip(x.keys)
(x.hcodes paired with x.keys ) is nonrepetitive.

(D3~2) 
If x.compare_by_identity? is true then
even the list x.keys is nonrepetitive.

(D3~3) 
If x.dflt_call? is true then
x.dflt is an instance of Proc .

(D3~4) 
If s is a direct instance of String
contained in x.keys
and x.compare_by_identity? is false
then
s is frozen.

x
,
the triple (x.hcodes, x.keys, x.values)
has the following equivalent forms:
singlelistform.
x.compare_by_identity?
is true then even keys are unique.
slotform.
slots) to lists of triples of the form (idx, key, value) such that
slotlists but within the whole hash,
slotlists respect the idx order (so that ordering in individual
slotsis
induced),
slotlists and if
x.compare_by_identity?
is true then even within the whole hash.
Example:
The following diagrams show a hash x
in the two above described forms.
Note that due to multiple occurrence of the 'a' key,
x.compare_by_identity?
is necessarily false.


Transitions S → S'
preserve the 6 member maps
.hcodes, …, .dflt_call? on frozen hashes.
 
True values of .compare_by_identity? are preserved.
(Once being set to true, this boolean attribute cannot be set to false.)

(.hash, .eql?(), .call())
where
.hash
is a function from objects to integers
(x.hash
is called the hash code of x
).
.eql?()
is a booleanvalued function on
O × O
encoding equality between objects.
.call()
is an objectvalued function on
Proc
s × Hash
es × O
.
x
and an object k
we say
that i
is a
resolution keyindex of k
in x
if either of the following is satisfied:
x.compare_by_identity?
is false and
i
is the smallest index such that
k.hash == x.hcodes[i]
and
either k == x.keys[i]
or k.eql?(x.keys[i])
,
x.compare_by_identity?
is true and
i
is the unique index such that
k == x.keys[i]
.
[]
is an objectvalued function on
Hash
es × O
assigning each hash x
and each object k
a value x[k]
as follows:
x[k] == x.values[i]
if
i
is the resolution keyindex of k
in x
,
else, if there is no such i
,
x[k] == x.dflt
if x.dflt_call?
is false, else
x[k] == x.dflt.call(x,k)
.
(Bignum, Float, Rational, Complex, .real, .imag)
where
Float
, Rational
and
Complex
are classes, direct descendants of Numeric
.
Bignum
is a direct descendant of Integer
.
Bignum
s are called bignums.
.real
and .imag
are functions from Complex
es to Numeric
s
that are not Complex
es.
Note:
The Fixnum < Integer < Numeric
class chain has
already been introduced, see
Immediate values.
The structure is subject to the following axioms:
(D4~1) 
Integer s are either Fixnum s or Bignum s.

(D4~2) 
Bignum , Float , Rational and Complex
are quasifinal
(in addition to Fixnum ).

(D4~3) 
Integer s are φvalue d by the integers ℤ .

(D4~4) 
Bignum s and Fixnum s have disjoint .φvalue images.

(D4~5) 
Float s are φvalue d by the floating point numbers ℱ .

(D4~6) 
Rational s are φvalue d
by pairs (n,d) from ℤ × ℤ such that

The .real and .imag maps
are preserved on all Complex es.

(Range, .start, .end, .exclude_end?)
where
Range
is a direct descendant of Object
.
Range
s are called ranges.
.start
and .end
are functions from Range
s to objects.
.exclude_end?
is a boolean attribute of Range
s.
The .start , .end and .exclude_end? maps
are preserved on all Range s.

invals
data (sub)fields in the ωobjects
data table as follows.
Applied to  Field Name 
Domain (Type) 
Description 
false 
value 
{FALSE} 

true 
value 
{TRUE} 

nil 
value 
{NULL} 

Encoding s 
name 
ℬ 
encoding name 
dummy? 
boolean  indicates statefulencoding without proper character handling 

ascii_compatible? 
boolean  indicates asciicompatible encoding  
Symbol s and String s 
bytes 
ℬ 
bytesequence together with encoding 
encoding 
ENUM 

valid_encoding? 
boolean  indicates whether bytes is a valid sequence w.r.t
encoding 

Array s 
length 
ℤ 
array length 
Hash es 
length 
ℤ 
hash length 
compare_by_identity? 
boolean  indicates hash resolution mode  
dflt 
OID  the hash's default object or evaluator  
dflt_call? 
boolean  indicates dflt interpretation mode 

Fixnum s 
value 
ℤ 
the φvalue of a fixnum 
Bignum s 
value 
ℤ 
the φvalue of a bignum 
Float s 
value 
ℱ 
the φvalue of a float 
Rational s 
numerator 
ℤ 
the first component of the φvalue 
denominator 
ℤ 
the second component of the φvalue , needs to be positive 

Complex es 
real 
OID  the realpart object 
imag 
OID  the imaginarypart object  
Range s 
start 
OID  range start 
end 
OID  range end  
exclude_end? 
boolean  range end exclusion indicator 
Notes:
invals
data.
(.idcat)
where
.idcat
is a partial function on estrings.
.idcat
are called
(lexical) identifiers,
x.idcat
is x
's identifier category.
(A0~1) 
The .idcat partial function categorizes estrings according
to the following table:
 
(A0~2)  Identifiers are subject to additional restrictions which are not specified in this document. 
.idcat
.
We will also use the word name
for nonmethod identifiers
and apply the categorization directly to symbols,
so that e.g. for a symbol s
,
s.estr.idcat == 'constantidentifier'
means
.
s
is a constant name
(Π, .met(), μ)
where
Π
is a set of anonymous methods,
disjoint from the set O
of objects,
π
is a distinguished element of Π
,
called the/a whiteout method, or simply whiteout
(the term adopted from []),
.met()
is
is a partial function from O × Υ
to
Π
, called own method map,
μ
is a symbol
such that μ.estr == "method_missing"
.
.met()
can be viewed as a subset of
O × Υ × Π
.
If x.met(s)
is defined then we say that
x
has own method s
or that
x
is a methodowner of s
.
If, in addition,
x.met(s)
is a whiteout,
then we say that
x
has own womethod s
or that
x
is a womethodowner of s
,
x.met(s)
is not a whiteout,
then we say that
x
has own nwomethod s
or that
x
is an nwomethodowner of s
.
An A1 structure has the following axioms:
Only actual objects can have own methods.  
Only includers can have own methods. 
If in initial state, an A1 structure satisfies the following:
(A1~3) 
The inheritance root r
is an nwomethod owner of μ
(the method_missing method).

Notes:
s
to become a method name.
In particular,
if x.met(s)
is defined then it is not required that
s.estr.idcat == 'methodidentifier'
, see notes to
Transitions.
Eigenclasses x.ec of Numeric s x
cannot have own methods.

.mowner()
from O × Υ × {true, false}
to O
,
called method owner map,
by
x.mowner(s, wo) == y 
iff 

false
to be the default value of wo
,
so that x.mowner(s)
means x.mowner(s, false)
.
Propositions:
x.mowner(s) == x
iff
x
is an nwomethodowner of s
.
x.mowner(s,wo).mowner(s,wo) == x.mowner(s,wo)
whenever x.mowner(s,wo)
is defined.
x
is a methodinheritor of s
if x.mowner(s, true)
is defined,
i.e.
if some of x.ancs
has own method s
.
We say that x
is an nwomethodinheritor of s
if x.mowner(s)
is defined.
By an inherited method map we mean
the partial function .met_h()
from O × Υ × {true, false}
to Π
defined by
x.met_h(s,wo) == x.mowner(s,wo).met(s)
x.mowner(s,wo)
is defined.
Again, the default value for wo
is false
.
smr()
from O × Υ
to O × Υ
defined as follows:
smr(x,s) == (x.ec.mowner(s), s)
if
x.ec.mowner(s)
is defined, else
smr(x,s) == (x.ec.mowner(μ), μ)
if
x.ec.mowner(μ)
is defined, else
smr(x,s)
is undefined.
Notes:
x.ec.mowner(s)
expresses the Ruby
method call mantra[]:
One to the right, then up.This is applied in both
search phases, (1) and (2).
μ
,
so that (3) never occurs.
.ec
and .aclass
Proposition:
For every object x
and every symbol s
,
x.ec.mowner(s) == x.aclass.mowner(s)
(either both sides are undefined or both defined and equal).
x
can actually start from the actualclass of x
.
Transitions S → S'
preserve .met() on frozen objects,
i.e. if x is a frozen includer,
then x.met(s) equals x.met'(s) .

.map()
can be arbitrarily (re)defined on nonfrozen objects.
Modifications of .map()
are accomplished via
transitions S → S'
of types (A)–(E) according to
the following table.
Transition parameters  Requested output condition  Ruby's correspondent(s)  
(A) New method definition  
(1) 

x.met'(s) == m 

(2) 

x.ec.met'(s) == m 

(B) Aliasing an inherited method  

x.met'(a) == x.met_h(s) 


(C) Whiteoutingan inherited method 


x.met'(s) == π 


(D) Removing an own nonwhiteout method  

x.met'(s) is undefined 


(E) Changing method visibility – see Method visibility transitions 
Notes:
x
is not specified in the rightmost column,
then it is assumed that x
equals self
unless
self == main
– in this case x == Object
.
s.estr.idcat == 'methodidentifier'
applies
to the method name s
(or to the alias a
).
In (b) cases, no such restriction applies, as shown in the following example.
class X define_method ("") { self } define_method ("1 + 1") { 3 } alias_method "@a", "" end p X.new.send("").send("@a").send("1 + 1") #> 3 p X.instance_methods(false) #> [:"", :"1 + 1", :@a] class X undef_method "1 + 1" remove_method "", "@a" end p X.instance_methods (false) #> []
(.pty(), κ)
where
.pty()
is a partial function from O × Υ
to
O
, called property map,
κ
is a symbol
such that κ.estr == "const_missing"
.
.pty()
can be viewed as a subset of
O × Υ × O
.
We call elements of the set Υ × O
properties.
We say that an object x
has own property (s,y)
if x.pty(s) == y
.
We might just say that x
has own property s
.
We categorize properties according to .idcat
:
Symbol s 
Property (s,y) category 
s.estr starts with an uppercase letter 
constant 
s.estr starts with "@ "
but not with "@@ " 
instance variable 
s.estr starts with "@@ " 
class variable 
s.estr starts with "$ " 
global variable 
s.estr starts with a lowercase letter or with _ 
local variable 
Notes:
Ruby object model.
An A2 structure has the following axioms:
(A2~1)  Only actual objects can have own properties. 
(A2~2)  Only includers can have own constants. 
(A2~3)  Only includers can have own class variables. 
(A2~4) 
Only the Kernel module can have global variables.

Note:
Global variable ownership is a rather artificial concept.
We have chosen the Kernel
as the owner, because it owns
the global_variables
method for global variable enumeration.
If in initial state, an A2 structure satisfies the following:
(A2~5) 
The metamodule root m is an nwomethod owner of
κ (the const_missing method).

weak formof the following condition applies:
(A2~6*) 
For every includers x , y ,
and every class variable symbol s
such that both x.pty(s) and y.pty(s) are defined,
each of the following conditions in its own right is sufficient
to imply x.pty(s) == y.pty(s)

weak formlooks like is not specified in this document. Neither are specified transition rules or resolution rules which seem to be even more complicated.
Note: Class variables are considered a controversial Ruby feature.
.cowner()
from O × Υ
to O
defined by
x.cowner(s) == y iff


Propositions:
x.cowner(s) == x
iff
x
is a constantowner of s
.
x.cowner(s).cowner(s) == x.cowner(s)
whenever x.cowner(s)
is defined.
x
is a constantinheritor of s
if x.cowner(s)
is defined,
i.e.
if some of x.ancs
has own constant s
.
By an inherited constant map we mean
the partial function .cst_h()
from O × Υ
to O
defined by
x.cst_h(s) == x.cowner(s).pty(s)
x
is a constantinheritor of s
.
.powner()
, the property owner map,
and .pty_h()
, the inherited property map,
as extensions of
.cowner()
and .cst_h()
, respectively.
.powner()
is a partial map
from O × Υ
to O
defined by
(1) x.powner(s) == x.cowner(s) 
if s is a constant name
and x.cowner(s) is defined, 
(2) x.powner(s) == x 
if s is an instance variable name
and x.pty(s) is defined, 
(3) (value not specified) 
if s is a class variable name
and (condition not specified), 
(4) x.powner(s) == Kernel 
if s is a global variable name
and Kernel.pty(s) is defined, 
(5) x.powner(s) is undefined otherwise. 
.pty_h()
is a partial map
from O × Υ
to O
defined by
x.pty_h(s) == x.powner(s).pty(s)
whenever x.powner(s)
is defined.
Notes:
.pty_h()
is only related to inheritance in cases (1) and (3).
.pty_h()
factors through
.powner()
even for class variables.
qcr()
from O × Υ
to O × Υ
defined as follows:
qcr(x,s)
is undefined if x
is not an includer
or s
is not a constant name, else
qcr(x,s) == (x.cowner(s), s)
if
x.cowner(s)
is defined, else
qcr(x,s) == (x.ec.mowner(κ), κ)
if x.ec.mowner(κ)
is defined, else
qcr(x,s)
is undefined.
qcr(x,s) == (y,t)
then we say that (y,t)
is
a qualified constant resolution of (x,s)
.
Notes:
qcr(x,s) == (y,t)
is defined in phase (1), then
y.pty(t)
equals the evaluation x::<s.estr>
(for example, if s.estr == "A"
, then
y.pty(t)
equals x::A
).
qcr(x,s) == (y,κ)
is defined in (2), then
the method y.met(κ)
gets called with x
as the receiver and s
as the
argument.
κ
, so that phase (3) never occurs.
Object
class are considered
toplevel constantsnot designed for referencing by descendants. If
qcr(x,s) == (Object,s)
and x != Object
then (in nonnil $VERBOSE
mode)
a warning is issued.
s
the expression ::<s.estr>
is equivalent to x::<s.estr>
with
x
being equal to Object
.
The qcr
map can be expressed as a method of Module
as follows:
class String def constant_name?; !!match(/^[AZ]\w*$/) end end class Module def cowner(s) ancs.find{x x.const_defined?(s, false)} end def qcr(s) !s.to_s.constant_name? ? nil : (o = cowner(s)) ? [o, s.to_sym] : respond_to?(t = :const_missing, true) ? [method(t).owner, t] : nil end end
uqcr()
from Υ
to O × Υ
.
The start point x
is obtained by
x == nesting[0]
if the nesting cursor nesting
is nonempty, else
x == main.ec
otherwise, i.e. if the current nesting is empty.
q
is defined by
q == nesting + x.ancs + Object.ancs
if x
is a module,
q == nesting + x.ancs
otherwise, i.e. if the start point is a class or
an eigenclass.
uqcr
map is then defined as follows:
uqcr(s)
is undefined if s
is not a constant name, else
uqcr(s) == (w, s)
if
w
is the leastindexed member of q
such that w.pty(s)
is defined, else, if no such w
exists,
uqcr(s) == (x.ec.mowner(κ), κ)
if x.ec.mowner(κ)
is defined, else
uqcr(s)
is undefined.
uqcr(s) == (y,t)
then we say that (y,t)
is
an unqualified constant resolution of s
.
Notes:
uqcr(s)
corresponds to the evaluation of <s.estr>
– i.e. there is no doublecolon (::
) before <s.estr>
.
uniq
operation (removing duplicate members) to be applied
to the lookup sequence q
.
nesting == [r]
then constants
owned by the Object
class are not visible via
the unqualified constant resolution
– they must be referenced using the ::
prefix.
Example (using another class that is not a descendant of Object
):
class A < BasicObject def self.const_missing(s); :missing end p [Module, ::Module] # [:missing, Module] end
The uqcr
map can be expressed as a method
of Array
as follows:
$main = self class Array def uqcr(s) return nil if !s.to_s.constant_name? x = first  $main.ec q = self + x.ancs + (::Class === x ? [] : ::Object.ancs) o = q.find{y y.const_defined?(s, false)} o ? [o, s.to_sym] : x.respond_to?(t = :const_missing, true) ? [x.method(t).owner, t] : nil end end
Note:
The method must be called with the current nesting as the receiver,
i.e. Module.nesting.uqcr(s)
.
state, in particular, they can
Statefulnessof
Fixnum
s is demonstrated in the following code.
class Fixnum def false(i = 1) @n_falsified = 0 @n_falsified += i self end def report "#{self} falsified #{@n_falsified  0} times" end end puts 5.report # 5 falsified 0 times puts 6.report # 6 falsified 0 times puts 5.false.report # 5 falsified 1 times puts 5.false.report # 5 falsified 2 times puts 6.false.report # 6 falsified 1 times
Transitions S → S'
preserve .pty(s) on frozen objects,
except for global variables s ,
i.e. if x is a frozen object
and s is a symbol that is not a global variable name,
then x.pty(s) equals x.pty'(s) .

.pty()
can be arbitrarily (re)defined on nonfrozen objects.
Modifications of .pty()
are accomplished via
transitions S → S'
according to the following table:
Transition parameters  Requested output condition  Ruby's correspondent(s) 
(A) Property assignment  

x.pty'(s) == y 

(B) Property removal  

x.pty'(s) is undefined 

Notes:
x
is not specified in the rightmost column, then
x
equals the artificial owner Kernel
if s
is a global variable name, else
x
equals Object
if self == main
, else
x
equals self
.
.cparent
function is not directly supported,
and, in general, is not even obtainable.
The builtin Module
's method x.name
provides a global containment pathof
x
in
one of the following forms ^{∗}:
A::B::C
, if x.croot
equals Object
,
#<Class:0xaafc40>::A::B::C
, otherwise
(i.e. if x.croot
is an eigenclass).
x.cparent
means resolving the path
without the last segment.
Such a resolution might not yield consistent results,
as discussed in the following subsections.
Note:
(∗)
x.name
may be even undefined, as shown in the following section.
(CNC~0) 
the pathname estrings x.cancs.map{ a a.cname.estr }
are (loosely) concatenable
for every includer x .

X = Object.const_set("X\u00e1".encode('utf8'), Class.new) class X Y = const_set("Y\u00e1".encode('iso88592'), Class.new) end p X::Y.name # raises Encoding::CompatibilityError
.cname
is injective on each sibling set, i.e.
(CNC~1) 
for every includers x , y with a containment parent,
x.cparent == y.cparent and
x.cname == y.cname implies
x == y .

class X class Y; end Z = Y class_eval { remove_const :Y } class Y; end end x = X y = X::Y z = X::Z puts "#{y.object_id}>#{y}" puts "#{z.object_id}>#{z}"The code produces three different classes,
x
, y
and z
,
such that
y.cparent == z.cparent == x
, and
y.cname == z.cname == "Y"
.
Module
's method
remove_const
which would prevent, at least to some extent,
sibling inconsistencies.
class Module alias toS to_s alias __remove_const remove_const; private :__remove_const def remove_const(sym) c = const_defined?(sym, false) ? const_get(sym,false) : nil if c.kind_of?(Module) && c.toS.match(Regexp.new("((\\:\\:)(^))#{sym}$")) raise NameError.new( "Cannot remove module/class :#{sym} from #{toS}", sym) end __remove_const(sym) end end
(CNC~2) 
x.cparent.pty(x.cname) == x
for every includer x with a containment parent.

remove_const
modification,
(b) seems to be preventable only by convention.
(When in $VERBOSE
mode,
Ruby issues a warning about an already initialized constant
.)
(CNC~3) 
x ≤ y and y == b.cparent
implies
x.cst_h(b.cname) ≤ b .

class X def a; @a end def initialize; @a = self.class::A.new end class A def report; self.to_s end end end class Y < X def initialize; super end class A < A; end end puts X.new.a.report #> #<X::A:0xab80d0> puts Y.new.a.report #> #<Y::A:0xab8028>
(.mvisibility())
where
.mvisibility()
is
a partial function from O × Υ
to
the set
{:private
, :protected
, :public
}.
The following axioms are required to hold:
x.mvisibility(s) is defined iff
x.met(s) is defined and is not a whiteout.

x.mvisibility(s) == v
we say
that the own visibility of s
in x
is v
.
We define inherited visibility .mvisibility_h()
by
x.mvisibility_h(x) == x.mowner(s).mvisibility(s)
x.mowner(s)
is defined.
uqmr()
from Υ
to O × Υ
defined as the partial application smr(self, _)
,
i.e.
uqmr(s) == smr(self, s)
whenever the right side is defined.
uqmr(s) == (y,t)
then we say that (y,t)
is an unqualified method resolution of s
.
The uqmr
map can be expressed as a method of
Object
as follows:
class Object def uqmr(s) t = :method_missing respond_to?(s, true) ? [method(s).owner, s] : respond_to?(t, true) ? [method(t).owner, t] : nil end end
qmr()
from
O × Υ
to
O × Υ
defined as follows.
qmr(x,s) == (x.ec.mowner(s), s)
if
x.ec.mvisibility_h(s)
is :public
, or
x.ec.mvisibility_h(s)
is :protected
and self.ec ≤ x.ec.mowner(s)
, else
qmr(x,s) == (x.ec.mowner(μ), μ)
if
x.ec.mowner(μ)
is defined, else
qmr(x,s)
is undefined.
qmr(x,s) == (y,t)
then we say that (y,t)
is a qualified method resolution of (x,s)
.
Notes:
x.ec.mvisibility_h(s)
is :private
or
x.ec.mvisibility_h(s)
is undefined, i.e.
x.ec.mowner(s)
is undefined.
x.ec.mvisibility_h(μ)
is irrelevant.
The qmr
map can be expressed as a method of Object
as follows:
class Object def qmr(x,s) if x.respond_to?(s, false) # public or protected o = x.method(s).owner if o.protected_instance_methods(false).include?(s) && !kind_of?(o) o = nil end if o then return [o, s] end end t = :method_missing x.respond_to?(t, true) ? [x.method(t).owner, t] : nil end end
.met()
and .pty()
partial maps,
.mvisibility()
is not guaranteed to be preserved on frozen objects:
class X; def m; end end p X.private_instance_methods(false) # [] X.freeze class X; private :m end p X.private_instance_methods(false) # [:m]Modifications of
.mvisibility()
are accomplished
according to the following table.
Transition parameters  Requested output condition  Ruby correspondents (visibility specifiers) 

Method visibility setting  
(1) 

x.mvisibility'(s) == v 

(2) 

x.ec.mvisibility'(s) == v 

Notes:
x
is not specified in the rightmost column,
then x
equals self
unless
self == main
– in this case x == Object
.
v
is implied by the method (visibility specifier) used.
private_class_method
or public_class_method
visibility specifiers:
class X; end class << X private; def m; end end ec = (x = X.new).singleton_class p ec.respond_to?(:m) # false ec.public_class_method(:m) p ec.respond_to?(:m) # true p ec.method(:m).owner # X.ec (#<Class:X>) p ec.singleton_methods(false) # [:m] p ec.singleton_class.public_instance_methods(false) # [] p ec.singleton_methods(false) # []The visibility of
:m
in x.ec.ec
has been changed from private
to public
but the owner of :m
remains X.ec
(according to ec.method(:m).owner
).
In addition, the last three line show inconsistency in :m
's ownership.
(Α,
ϙ(), ϻ(), ι(), ϰ(),
α(), β(), αɦ(), βɦ())
where
Α
is a set of
arrow datarepresentatives or just arrows,
disjoint from hitherto introduced sets,
ϙ(), …, βɦ()
are injective maps
to arrows with mutually disjoint ranges denoted
Α_{ϙ}, …, Α_{βɦ}
.
ϙ() is a partial map
from O × ℬ to Α ,

ϙ(x,s) is defined according to the table in
Internal property arrows.

ϻ() is a partial map
from O × ℤ to Α ,

ϻ(x,i) is defined iff x.incs[i] is defined.

ι() is a partial map
from Array s × ℤ to Α ,

ι(x,i) is defined iff x._list[i] is defined.

ϰ() is a partial map
from Hash es × ℤ to Α ,

ϰ(x,i) is defined iff x.keys[i] is defined.

α() is a partial map
from O × Υ to Α ,

α(x,s) is defined iff x.met(s) is defined.

β() is a partial map
from O × Υ to Α ,

β(x,s) is defined iff x.pty(s) is defined.

αɦ() is a partial map
from O × Υ to Α ,

αɦ(x,s) is defined iff
x is actual and x.ec.mowner(s) is defined.

βɦ() is a partial map
from O × Υ to Α ,

βɦ(x,s) is defined iff
x is actual and x.powner(s) is defined.

Symbols 
arrow constituents →  Source  Name (Key)  Owner  Attributes  Target  
Terminology for the set Α_{s} 
source 
idx 
hcode 
key / name 
owner 
mvisibility 
target 

ϙ 
internalpropertyarrows  internal arrows 
●  ●  ●  
ϻ 
inclusionlistarrows  ●  ●  ●  
ι 
arrayarrows  (external) ownarrows 
●  ●  ●  
ϰ 
hasharrows  ●  ●  ●  ●  ●  
α 
ownmethodarrows  ●  ●  ●  ●  
β 
ownpropertyarrows  ●  ●  ●  
αɦ 
previewmethodarrows  previewarrows  ●  ●  ●  ●  ●  
βɦ 
previewpropertyarrows  ●  ●  ●  ● 
ω
objects for our arrow formalization.
Instead, we use the set O
of objects directly, so that the
ωobjects
table can be considered split again into
(A) objects
and (B) a table of module inclusion lists.
This yields
Terminology  source Domain 
name 
target Domain 
Description 
selfarrows  objects  self (*) 
objects  identity arrow 
typesystemarrows  objects  terminative? 
boolean  basic type 
primary? 
boolean  
nonterminals  sc 
nonterminals  superclass  
eigenclasses  ce 
objects  eigenclass predecessor  
objects  ec 
eigenclasses  eigenclass successor  
includers  cparent 
includers  containment parent  
cname 
symbols (Υ ) 
containment name  
commonvaluearrows  objects  frozen? 
boolean  frozenness 
tainted? 
taintedness  
trusted? 
trust  
specialvaluearrows  some nonincluders 
value ,bytes ,dflt , … 
Object value fields, see Object internal value data. 
Note:
(*) This corresponds to the identity function .self
on O
.
Because of the dotnotation, there is no naming conflict with the already
introduced self
cursor.
ϙ
arrows and ϻ
arrows:ϙ
arrows and ϻ
arrows:




ι
arrows and ϰ
arrows:ι
arrows and ϰ
arrows:




α
arrows and β
arrows:α
arrows and β
arrows:





Applies to  Field Name 
Domain (Type) 
Description  Relevant field(s) in MRI 
ϙ arrows 
source

OID  the object  
name 
ℬ 
internal property name  
target
 mixed 
internal property value  
ϻ arrows 
source

OID  the includer  
idx 
ℤ 
member index  
target
 OID  i thincludee 

ι arrows 
source
(owner )

OID  the Array instance (owner) 

idx 
ℤ 
member index  
target
(value ) 
OID  the target object (value)  
ϰ arrows 
source
(owner )

OID  the Hash instance (owner) 

idx 
ℤ 
member index  
hcode 
ℤ 
hash code  
key 
OID  key  
target
(value ) 
OID  the target object (value)  
α arrows 
source
(owner )

OID  the source object (owner)  
name 
string  method name  
mvisibility 
ENUM_V  method visibility  part of flag (in rb_method_entry_t ) 

target
(value ) 
Π 
the target method (value)  def (in rb_method_entry_t ) 

β arrows 
source
(owner )

OID  the source object (owner)  
name 
string  property name  
target
(value ) 
OID  the target object (value) 





αɦarrows
and βɦarrows
data tables
which are sort of builtin database view.
Gray color indicates that except for the owner
column,
αarrows
(resp. βarrows
)
and αɦarrows
(βɦarrows
)
have the same field set.
αɦarrows 
βɦarrows 



a
emanating from a given object x
(i.e. such that a.source == x
)
we obtain a picture
about object data stratification.
Arrow set  Subset  Description 
ϙ arrows 
identity arrow  Object identity 
typesystem  Internal properties  
common values  
special values  
ϻ arrows 
Inclusion list  
ι arrows and ϰ arrows 
Array/hash members  
α arrows 
Own methods  
β arrows 
Own properties  
αɦ arrows 
Respondent methods  
βɦ arrows 
Inherited properties 
(.dyn_class?)
where
.dyn_class?
is a boolean attribute of classes indicating whether
the class is dynamic.
(A5~1)  All subclasses of a dynamic class are dynamic. 
(A5~2) 
Of the already introduced classes, only Proc is dynamic.

.dyn_class?
attribute, we
define the following attributes of objects:
.clontype
is an attribute of objects with possible values
'clone'
or 'none'
.
.dumptype
is an attribute of objects with possible values
'clone'
, 'ref'
or 'none'
.
objects x 
x.clontype 
x.dumptype 
eigenclasses  'none' 
'none' 
classes and modules such that x.croot != Object (in particular, anonymous classes and modules) 

immediate values
(false , true , nil , Fixnum s, Symbol s) 
'ref' 

Encoding s 

the inheritance root r
(i.e. the BasicObject class) 

Numeric s except Fixnum s 
'clone' 

includers such that x.croot == Object except r (i.e. fullnamedclasses and modules except BasicObject ) 
'clone' 
'ref' 
instances of dynamic classes
(Proc s, Method s, UnboundMethod s, …) 
'none' 

other objects
(objects that are not immediate values and not
instances of Module , Class , Encoding ,
Numeric and of dynamic classes) 
'clone' 
clone
and dup
methods of Kernel
create siblings in the primary inheritance.
Given a primary object x
(a class or, more typically, a terminal),
y = x.clone
y = x.dup
y
such that
.terminative?
and .ec_sc_pr
coincide on x
and y
.
The following table shows a correspondence between
clone
/dup
and new
.
The new method 
The clone method 
The dup method 

Application  x is a class 
Class.new(x.sc) 
x.clone 
x.dup 
x is a terminal 
x.class.new 
x.clone 
x.dup 

Hooks  initialize 
initialize_clone 
initialize_dup 

initialize_copy 

Procedure without hooks 





x.arrows
is defined as follows:
clone 
dup 


a.source.pr == x 
a.source == x 
except selfarrows and except the following:



Notes:
x
with
x.clontype == 'none'
is not supported.
r.clontype == 'none'
.
clone
versus dup
support for instances of Method
and UnboundMethod
.
This difference is not expressed by the above description.
ϰ
arrows.
a
from x.arrows
that is an own method arrow
(an α
arrow) the method a.target
is copied too.
This allows for proper copy of method dealiasing.
To describe this would require introducing
arrows for .orig_owner
and .orig_name
.
Marshal.dump
logic
by specifying sets x.objects
and x.arrows
of stored objects and arrows, respectively, for each dumpableobject
x
.
We proceed inductively
by defining sets x.objects(0)
, …, x.objects(n)
and x.arrows(0)
, …, x.arrows(n)
so that
x.objects(n)
(resp. x.arrows(n)
), if defined, is some subset of objects (resp. arrows)
reachable from x
by at most n
arrows.
The sets
x.objects
and x.arrows
are then either undefined
(in the case of a nondumpable
object x
)
or they are defined by
x.objects == x.objects(n)
and x.arrows == x.arrows(n)
n
is such that x.objects(n) == x.objects(n+1)
.
x.objects(0)
is undefined if x.dumptype == 'none'
, else
x.objects(0)
is the empty set if x.dumptype == 'ref'
, else
x.objects(0)
is undefined if x.ec
has an own method or property
(i.e. an α
 or β
arrow a
such that a.source == x.ec
), else
x.objects(0)
is the singleelement set {x}
.
x.arrows(0)
is undefined if x.objects(0)
is undefined, else
x.arrows(0)
is the the singleelement set {ϙ(x,'self')}
if x.objects(0)
is the empty set, else
x.arrows(0)
is the set of all arrows a
such that either (A) or (B) is
satisfied:
a.source == x
and a
is of one of the following types:
ϙ
arrow,
ι
arrow (array member),
ϰ
arrow (hash member),
β
arrow (own property, necessarily instance variable,
because x
is a pure instance (nonincluder)),
a.source.ce == x
and a
is one of the following types:
ϙ
arrow name
d sc
(so that a
corresponds to a .class
link
–
recall that x.ec.sc
equals x.class
for terminal x
),
ϻ
arrow,
(so that a
corresponds to an .ec.incs[i]
link
between x
and a module included in the eigenclass x.ec
).
n > 0
.
x.objects(n)
is undefined if
x.objects(n1)
is undefined, else if
y.objects(0)
is undefined for some object y
that is the target
of an arrow from x.arrows(n1)
,
x.objects(n)
is the set of all objects y
such that
y ∈ x.objects(n1)
or
y.dumptype == 'clone'
and
y
is the target of an arrow from x.arrows(n1)
.
x.arrows(n)
is undefined if x.objects(n)
is undefined, else
x.arrows(n)
is the set of all arrows a
such that
a ∈ x.arrows(n1)
, or
a ∈ y.arrows(0)
for some y ∈ x.objects(n1)
.
Comments:
.ec
arrow
are considered as a single shortcutarrow (case (B)).
x.dumptype == 'ref'
then x.objects
is defined as empty set but
x.arrows
is defined as a singleton set containing just the identity
arrow of x
. This means that just a referenceto
x
is dumped.
x.objects
can only contain pure instances (nonincluders).
Includers are dumped by reference.
x
is unsupported whenever there is an arrow path
ending in an object y
with y.objects(0)
undefined,
in particular, if y.dumptype == 'none'
.
(.orig_owner, .orig_name)
where
.orig_owner
is a function from the set
Π ∖ {π}
to includers
assigning each nonwhiteout method its original owner.
.orig_name
is a function from the set
Π ∖ {π}
to Υ
assigning each nonwhiteout method its original name.
(A6~1) 
For every nonwhiteout method α ,

Notes:
(x,s) == (α.orig_owner, α.orig_name)
then any of the following cases may occur:
x.met(s) == α
(the most typical case),
x.met(s)
is undefined or equals π
,
x.met(s)
is an nwomethod different from α
.
The .orig_owner and .orig_name are preserved.

overwritingthe original method owner is shown in the following code.
def def_report class_eval { def report; super end } end class A; def report; 'A' end end class B; def report; 'B' end end class X < A; def_report; end class Y < B; def_report; end p Y.new.report #> B p X.new.report #> NotImplementedError
Note:
The example demonstrates that the problem is not restricted to eigenclasses,
as suggested by the error message
(super from singleton method that is defined to multiple classes is not supported
).
super
)
pmr()
from
O × O × Υ
to
O × O × Υ
.
The assignment (x,o,s) ↦ (x,p,t)
has the following semantics:


(x,o,s)
,
the triple (x,p,t) == pmr(x,o,s)
is
defined as follows:
pmr(x,o,s)
is undefined if
either
o.met(s)
is undefined or a whiteout
or
o
does not occur in x.ec.ancs
.
α = o.met(s)
.
i
be the smallest such that
x.ec.ancs[i] == α.orig_owner
.
If no such i
exists then apply (C).
j
be the smallest such that i < j
and
x.ec.ancs[j]
is a method owner of α.orig_name
.
If no such j
exists then apply (C).
x.ec.ancs[j].met(α.orig_name)
is a whiteout then apply (C).
pmr(x,o,s) = (x, x.ec.ancs[j], α.orig_name)
.
pmr(x,o,s) == (x, x.ec.mowner(μ), μ)
if
x.ec.mowner(μ)
is defined, else
pmr(x,o,s)
is undefined.
Notes:
pmr
map.
Examples:
C#report
results in skippingof
B#report
.
class O; def report; "O" end end class A < O; def report; "A" + super end end class B < A; end class C < B; alias report report end class B; def report; "B" end end class A; remove_method :report end puts C.new.report #> AO
M
in B
's ancestor list causes
a cycle of super
s.
module M def report(i=0); "M(#{i})" + (i < 4 ? super(i+1) : " ...") end end class A; end class B < A; include M end class A; include M end p B.ancestors #> [B, M, A, M, Object, Kernel, BasicObject] p B.new.report #> "M(0)M(1)M(2)M(3)M(4) ..."
A
inherits the report
method from N
.
The original method owner of N#report
is M
.
This module does NOT appear among A
's ancestors
until the reinclusion of N
into A
.
module M; def report; super end end module N; end class O; def report; 'O' end end class A < O; include N end module N; include M end module N; alias report report end A.new.report rescue puts $!.inspect #> super: no superclass method p A.ancestors.take(4) #> [A, N, O, Object] class A; include N end p A.ancestors.take(5) #> [A, N, M, O, Object] puts A.new.report #> O
blanknessconditions imposed by our axioms. In particular, it is possible to have semiactual objects
x
such that
x
has own includees,
x
has own methods,
x
has own properties (constants or instance variables).
.ec_ref
hack
ec_ref
which allows to reference an eigenclass x.ec
of a class x
without x.ec
's actualization.
The method makes a guessof
x.ec
's object identifier
and uses ObjectSpace._id2ref
,
see
The inverse to .object_id
.
class Class EC_ID_DELTA = (x = Class.new).singleton_class.object_id  x.object_id def ec_ref ObjectSpace._id2ref(object_id + EC_ID_DELTA) end endThough being platform/environment dependent by nature, the code probably works in most cases.
_class_method
hack
private_class_method
and public_class_method
visibility specifiers:
class X; end; class Y < X; end def X.m; end nnt_delta_report Y.private_class_method(:m) nnt_delta_report # 0 ec = Y.singleton_class nnt_delta_report # 1 p ec.private_instance_methods(false) # [:m]
!
, ==
, !=
or equal?
,
Ruby does not provide reflection for
blank slate objects.
Most methods that are stated to be provided for objects
are actually provided for Object
s.
A test whether an object x
is not a blank slate object
is performed by
Object === x
true
if x
is an Object
,
i.e. x
is not a blank slate object).
.object_id
object_id
of Object
provides an injective map from actual objects to integers represented by
Fixnum
or Bignum
instances.
Immediate values except Symbol
s have a fixed valuetoid prescription.
Object x 
Class of x 
x.object_id 
Class of x.object_id 

false 
FalseClass 
0 
Fixnum 

true 
TrueClass 
2 

nil 
NilClass 
4 

x 
Fixnum 
2*x + 1 


All other objects  No fixed prescription  Fixnum 
.object_id
ObjectSpace._id2ref(x)
provides an inverse to y.object_id
:
ObjectSpace._id2ref(x) == y
if
y.object_id == x
for some, necessarily unique,
object y
.
y
, then an exception is raised.
Note:
The method also works for semiactual objects, see
The .ec_ref
hack.
.toX
map
.toX
function
is an injective map from objects to hexadecimally encoded integers.
It is of the form
x.toX ≝ "%#08x" % [x.oid2]
.oid2
is a variant of .object_id
.
The string "0x2fe00e"
is an example of a .toX
value.
Note:
The 8
digit which is used in the string format
determines string length and is platform dependent.
The conversion between .object_id
and .oid2
is partially described in the following table.
x.oid2 
Applicability condition 
x.object_id 
x is
false , true , nil or a nonnegative
Fixnum

?  x is a negative Fixnum

?  x is a symbol

2 * x.object_id 
x is NOT an immediate value

.toS
to_s
of Object
and Module
provide a map from objects to strings represented by
String
instances.
If
In contrast to object_id
, the
to_s
method is – by convention –
subject to override.
We therefore refer to an alias method .toS
which can be
established by
class Object; alias toS to_s end class Module; alias toS to_s endThe
.toS
function is defined according to the following rules:
x.toS 
Applicability condition  
"Object" 
x == Object 

x.cpathname 
x.croot == Object and x != Object 

"#<Class:%s>:%s" %

x is a named class or module and x.croot an eigenclass


"#<%s:%s>" % [x.class.toS, x.toX] 
x is a nonincluder (pure instance) 

x is an anonymous module  
"#<Class:%s>" % [x.toX] 
x is an anonymous class 

"#<Class:%s>" % [x.ce.toS] 
x is an eigenclass 
.toS
.
Each row contains a representantive x
of a partition of primary objects
according to the following criteria:
x
a named module?
x
or of x.class
if x
is a nonincluder.
x
terminal?
X::Y
and X.ec::A
are classes
and X::M
and X.ec::N
are modules.
Containment type  x.ec(i).toS
(string representation of i th eigenclass
of a primary object x )


↓  x ↓ 
i →

0 
1 
A  X::Y 
X::Y 
#<Class:X::Y> 

X::Y.new 
#<X::Y:0xab4590> 
#<Class:#<X::Y:0xab4590>> 

B  Class.new 
#<Class:0xab43f8> 
#<Class:#<Class:0xab43f8>> 

↳ .new 
#<#<Class:0xab43f8>:0xab4200> 
#<Class:#<#<Class:0xab43f8>:0xab4200>> 

C  X.ec::A 
#<Class:0xad3d00>::A 
#<Class:#<Class:0xad3d00>::A> 

X.ec::A.new 
#<#<Class:0xad3d00>::A:0xaaf9a0> 
#<Class:#<#<Class:0xad3d00>::A:0xaaf9a0>> 

A  X::M 
X::M 
#<Class:X::M> 

C  X.ec::N 
#<Class:0xaae968>::N 
#<Class:#<Class:0xaae968>::N> 
Observations:
Denote y = x.ec(i)
.
n
the number of trailing '>
'
characters of y.toS
.
Then for the eigenclass index i
the following holds:
i == n  1
if y.toS
contains the string ":0x
"
not followed by a string containing "::
",
i == n
otherwise.
i > 0
,
the substring of y.toS
delimited by the last occurrence of a single ':
'
and the first occurrence of trailing '>
' equals
x.toS
if x
is a named class or module
with x.croot
equal to Object
,
x.croot.toX + ">::" + x.cpathname
if x
is a named class or module
with x.croot
an eigenclass,
x.toX
otherwise.
y
is
terminative cannot be detected from
y.toS
alone
(X.ec::A.toS
and
X.ec::N.toS
have same format).
y
,
to obtain the eigenclass index y.eci
and
the primary object y.pr
from the
string representation y.toS
.
This can be realized by the following code:
class Object def eci (s = toS).length  s.index(/[>]*$/)  (s.match(/:0x(?!.*\:\:)/)? 1:0) end def pr_chunk (m = toS.match(/[^:]\:(?!\:)(?!.*[^:]\:[^:])(.*[^>])[>]+$/)) ? m[1] : toS end def pr if eci == 0 then return self end c = pr_chunk if c.include?(">") # the complicated case: pr.croot is an eigenclass r = (m = c.match(/^(0x.*)[>]::(.*)$/)) ? m[1] : raise("???") r = ObjectSpace._id2ref(eval(r)/2) return r.class_eval("self::" + m[2]) end (p = ::Object.class_eval(c)).instance_of?(Fixnum) ? ObjectSpace._id2ref(p/2) : p end endUnfortunately, the
.pr
implementation requires class Module def cname (m = toS.match(/(^(::))([^:>]+)$/)) ? m[3] : nil end def cpathname (m = toS.match(/(^Object^(::))([^<>]*)$/)) ? m[3] : "" end def croot_toS ((s = toS).match(/^[^>]*$/)) ? "Object" : (m = s.match(/(.*?)::.*[^>]$/)) ? m[1] : toS end def croot if eci > 0 then return self end n = croot_toS m = n.match(/\:(0x[^>]*)/) m ? ObjectSpace._id2ref(eval(m[1])/2) : eval("::" + n) end def cancs a = [croot] cpathname.split("::").each { x a << a.last.const_get(x, false) } a.reverse! end def cparent(i = 1); cancs[i] end end
O
are described in the following table.
Subset of O 
Way of enumeration  
Immediate values 
false , true , and nil 
Literalenumeration 
Fixnum s 
Not supported (?)^{∗}  
Symbol s 
Using Symbol.all_symbols 

Classes and terminals that are not immediate values  Using ObjectSpace.each_object 

Actual eigenclasses  Not supported (?) 
Note:
(∗)
Fixnum
s can be enumerated by domain enumeration
.
The not supported status means that there is no efficient builtin way
(known to the author) of enumerating just the fixnums with nondefault state
(see Immediate values revisited).
Relations, (partial) functions and constants defined in this document 
Ruby 1.9 builtin or semibuiltin correspondents  
Notation  Description  
x.sc 
the superclass of a nonterminal x 
x.superclass 
x.ec 
the eigenclass of x (the successor of x in the eigenclass chain) 
x.singleton_class
with the following limitations:

x.ec(i) 
i th eigenclass successor of x 
i > 0 ? x.singleton_class.ec(i1) : x 
x.ce 
the predecessor of x in the eigenclass chain 
Obtainable from x.toS , see x.ce(i) .
Note:
Internally, 
x.ce(i) 
i th eigenclass predecessor of x 
(j = x.eci  i) > 0 ? x.pr.ec(j) : nil

x.pr 
the primary object of x 
Obtainable from x.toS using
ObjectSpace._id2ref . 
x.eci 
the eigenclass index of x 
Obtainable from x.toS . 
r 
the inheritance root  BasicObject 
c
(equal to r.class )

the instance root, the metaclass root 
Class 
m 
the metamodule root  Module 
¤
(equal to r.croot )


Object 
¤.incs[0]
if having its initial value 
the conventional MRO root  Kernel
Note:
More precisely, the conventional MRO root equals the pair 
r.ec 
the implicitmetaclass root  BasicObject.singleton_class 
c.ec 
the usual actualclass root  Class.singleton_class 
x.class 
the class of x 
x.class 
x directinstanceof y 
x.class equal to y 
x.instance_of? y 
x instanceof y 
x.class is a subclass of or equal to y 
x.class ≤ y && y.class == Class
Note:

x kindof y 
x.ec ≤ y 
x.kind_of? y 
x.incs 
own inclusion list of an includer x

Obtainable via included_modules . Equals

x ownincluderof y 
includer x
is an own includer of a module y 
x.include?(y) && !x.superclass.include?(y)
is not reliablewith respect to repetitive ancestor lists. 
x includerof y 
x.include? y (method of Module ) 

x ≤ y 
HM descendancy  x <= y (method of Module )
Similarly, methods < , >= , > are defined with
obvious meaning.


inheritance ancestors
of a nonterminal x ,
starting with x itself 
Obtainable using x.superclass . Equals

x.hancestors 
without eigenclasses 
x.ancestors  x.included_modules 
x.ancs 
MRO ancestors of an includer x ,
starting with x itself 
Obtainable using x.superclass and
x.incs . Equals

x.ancestors 
without eigenclasses 
x.ancestors (method of Module ) 
x.terminal? 
is an object x terminal? 
x.class != Class

x.class? 
is an object x a class? 
x.class == Class && x == x.ancestors[0]

x.eigenclass? 
is an object x an eigenclass? 
x.class == Class && x != x.ancestors[0]

x.terminative? 
is an object x terminative? 

x.metaclass? 
is an object x a metaclass? 
Class == x.class && !!(Class >= x)

x.module? 
is an object x a module? 
x.kind_of?(Module) && !x.kind_of?(Class)

x.metamodule? 
is an object x a metamodule? 
x <= Module && x != Class && x.class?

x.blank_slate? 
is an object x a blank slate object? 
!(Object === x)

x.frozen? 
is an object x frozen? 
x.frozen? 
x.tainted? 
is an object x tainted? 
x.tainted? 
x.trusted? 
is an object x trusted? 
!x.untrusted? 
x.klass 
the virtual connection to x 's eigenclass 
Not supported (?)
Note:
Internally, at the 
x.aclass 
the actualclass of x 
Not supported (?) 
x.actuals 
actual eigenclassesorself of a primary object x 
Not supported (?) 
x.cparent 
the containment parent of an includer x 
See Containment reflection 
x.cname 
the containment name of an includer x 

x.cpathname 
the containment pathname of an includer x 

x.croot 
the containment root of an includer x 

x.cancs 
containment ancestors of an includer x 

nesting 
the current nesting  Module.nesting 
self 
the current object  self 
main 
the main context  Not directly supported (?) but recordableby $main = self 



x nwomethodownerof s 
includer x has own method s
which is not a whiteout

methods.include?(s)
where methods equals
x.private_instance_methods(false) +
x.protected_instance_methods(false) +
x.public_instance_methods(false)
(methods of Module ).

x nwomethodinheritorof s 
includer x
owns or inherits a nonwhiteout method s

Same as with nwomethodownerof but with
(false) omitted (or replaced by (true) )

x womethodownerof s
(x.met(s) == π ) 
includer x
has own whiteout method s

Not supported (?) 
x womethodinheritorof s
(x.met_h(s) == π ) 
includer x
inherits a whiteout method s

Not supported (?) 
x.mowner(s) 
owner of a nonwhiteout method s
inherited by an includer x 
x.instance_method(s).owner

x.ec.mowner(s) 
owner of a nonwhiteout method s
inherited by an eigenclass x.ec 
x.method(s).owner
(methods of Object and Method , respectively)

x constantownerof s 
includer x has own constant s 
x.const_defined?(s, false)

x constantinheritorof s 
includer x owns or inherits constant s 
x.const_defined?(s, true)

x.cowner(s) 
owner of a constant s
inherited by an includer x 
x.ancs.find{ y y.const_defined?(s, false)}

x.mvisibility(s) 
own method visibility of s in an includer x

[:private,:protected,:public].find{v x.send( "#{v}_instance_methods",false).include?(s) } 
x.mvisibility_h(s) 
inherited method visibility of s
in an includer x

Same as with .mvisibility
but with false replaced by true .

uqcr(s) 
unqualified constant resolution of s 
See Unqualified constant resolution 
qcr(x,s) 
qualified constant resolution of (x,s) 
See Qualified constant resolution 
uqmr(s) 
unqualified method resolution of s 
See Unqualified method resolution 
qmr(x,s) 
qualified method resolution of (x,s) 
See Qualified method resolution 
pmr(x,o,s) 
parent method resolution of (x,o,s) 
Not supported (?) 
x.hcodes 
list of hashcodes of a hash x 
Not supported (?) 
x.keys 
list of keys of a hash x 
x.keys 
x.values 
list of values of a hash x 
x.values 
x.dflt 
the default value/evaluator of a hash x 
x.default_proc  x.default 
x.dflt_call? 
the .dflt interpretation switch of a hash x 
!!x.default_proc 
Method name  Owner  Semantics 
singleton_methods 
Kernel 

instance_methods 
Module 
x.instance_methods(inherit) equals
x.protected_instance_methods(inherit)
+
x.public_instance_methods(inherit)
up to member order

Owner  Methods 
BasicObject 
!
==
!=
equal?
initialize
instance_eval

Object (Kernel ) 
class
clone
define_singleton_method
dup
eql?
extend
freeze
frozen?
hash
initialize_dup
initialize_clone
initialize_copy
instance_of?
kind_of?
method
object_id
send
singleton_class
singleton_methods
taint
tainted?
to_s
untaint
untrusted?

Module 
ancestors
class_eval
const_defined?
const_get
const_missing
const_set
constants
define_method
extended
include
include?
included_modules
instance_method
instance_methods
method_defined?
module_eval
module_function
name
private
private_class_method
private_instance_methods
private_method_defined?
protected
protected_instance_methods
protected_method_defined?
public
public_class_method
public_instance_method
public_instance_methods
public_method_defined?
remove_const
remove_method
to_s
undef_method

Module.ec 
nesting
new 
Class 
new
superclass

Class.ec 
new 
Kernel 
global_variables
lambda
p
puts

Array 
[]
+
<<
drop
each
empty?
first
include?
index
join
last
length
map
map!
pop
push
replace
reverse
select
shift
slice
uniq
unshift
zip

String 
[]
%
+
bytes
chars
encode
encoding
length
match
to_sym

Encoding 
ascii_compatible?
dummy?
name

Hash 
[]
compare_by_identity?
default
default_proc
keys
values

Method 
name
owner
receiver
unbind

UnboundMethod 
bind
name
owner
receiver

Symbol 
to_s

Symbol.ec 
all_symbols

ObjectSpace.ec 
_id2ref
count_objects
each_object

Rational 
denominator
numerator

Complex 
imag
real

Range 
begin
end
exclude_end?

Marshal.ec 
dump

Notes:
Object
indicates that this class is stated to be method owner only by convention.
new
of Class
.
In the expression Class.new
,
the instance method of the Class
class is invoked.
This can be introspected by Class.method(:new).owner == Class
.
new
of Module
.
ℍ
corresponds to set inclusion ⊆
.
.ec ◦ ℍ
(*)
corresponds to set membership ∈
.
Note:
(*)
.ec ◦ ℍ
equals
.ec ◦ ≤
rangerestricted to nonterminals.
(In this restriction, no object can be kindof a module.)
The .ec ◦ ≤
relation is introduced in the S2 structure
and corresponds to the .kind_of?
/ .is_a?
reflection method.
The document also provides alternative axiomatization of S1 structures.
Μ
relation
(selforownincluderof).
The document
[]
uses the ≤ symbol for .sc
inheritance
(which is called simply inheritance).
In addition, both ≤ and Μ
are reflexive
over the whole set of objects, including all terminals.
Ruby Hacking Guide, 2004, , Hawthorne Press 2008, http://www.hawthornepress.com/WebPage_RHG.html)  ,
Union mounts/writable overlays design, 2009, LWN.net http://lwn.net/Articles/355351/  ,
The WellGrounded Rubyist, Manning Publications 2009  ,
Abstract State Machines: A Method for HighLevel System Design and Analysis, Springer 2003  ,
Introduction to lattices and order, Cambridge University Press 2002  ,
The double inclusion problem, 2005, http://eigenclass.org/hiki/The+double+inclusion+problem  ,
Ruby and otherwise, http://www.klankboomklang.com/category/rubyinternals/  ,
The Ruby Programming Language, O'Reilly 2008  ,
Putting Metaclasses to Work, Addison Wesley 1998  ,
Evolving algebras: An attempt to discover semantics, in Current trends in theoretical computer science: essays and tutorials, Grzegorz Rozenberg, Arto Salomaa (eds), World Scientific 1993, http://www.eecs.umich.edu/gasm/tutorial/tutorial.html  ,
Evolving Algebras 1993: Lipari Guide, in Specification and Validation Methods, E. Börger (ed.), Oxford University Press 1995  ,
The Ruby Object Model  Structure and Semantics, 2009, http://www.hokstad.com/rubyobjectmodel.html  ,
Ruby Draft Specification, 2009, http://rubystd.netlab.jp/  ,
Ruby's Implementation Does Not Define its Semantics, 2010, http://yehudakatz.com/2010/02/25/rubysimplementationdoesnotdefineitssemantics/  ,
The Secret Life Of Singletons, 2008, http://banisterfiend.wordpress.com/2008/10/25/thesecretlifeofsingletons/  ,
Ruby objects, classes and eigenclasses, 2008, http://mccraigmccraig.wordpress.com/2008/10/29/rubyobjectsclassesandeigenclasses/  ,
nLab tree, 2011, http://ncatlab.org/nlab/show/tree#as_digraphs_6  ,
The Linux VFS Model: Naming structure, 2011, http://www.atalon.cz/vfsm/linuxvfsmodel/  ,
The Ruby Object Model: Comparison with Smalltalk80, 2012, http://www.atalon.cz/rbom/rubyobjectmodel/cosmalltalk/  ,
The Ruby Object Model: S1 superstructure representation, 2012, http://www.atalon.cz/rbom/rubyobjectmodel/s1rep/  ,
Ruby Object Model – The S1 structure, 2012, http://www.atalon.cz/rbom/rubyobjectmodel/rboms1.pdf  ,
Object Membership: The core structure of objectoriented programming, 2012, http://www.atalon.cz/om/objectmembership/  ,
Metaprogramming Ruby, Pragmatic Bookshelf 2010  ,
Read Ruby, http://ruby.runpaint.org  ,
Ruby Doc, http://rubydoc.org  
Ruby Forum, http://www.rubyforum.com  
The Python 2.3 Method Resolution Order, 2003, http://www.python.org/2.3/mro.html  ,
The Ruby Object Model and Metaprogramming, 2008, http://pragprog.com/screencasts/vdtrubyom/therubyobjectmodelandmetaprogramming  ,
Wikipedia: The Free Encyclopedia, http://wikipedia.org 
March  2  2011  The initial release. 
September  2  2011 
Major update. Main changes:

October  18  2011  Improved description of module inclusion. 
January  2  2012 

January  4  2012  An example of parent method resolution added. 
January  11  2012 

Febuary  10  2012 

March  2  2012 

April  3  2012  Renumbering of S4~ conditions so that conditions that only depends on S1 are listed first. 
April  23  2012  New appendix: The S1 structure (a PDF article). 
April  27  2012 
Note about Class.ec not being an owner of new .

June  21  2012 

June  28  2012 
Corrected & improved description of constant resolution
(qcr /uqcr ).

June  29  2012  The definition of a primorder algebra introduced explicitly (moved from []). 
October  10  2012  A reference to object membership [] added. 