Object Membership
with Prototypes

As an appendix to [] and [], this document describes the object membership structure (O, ϵ) in its extension OΘ by prototypes. Each eigenclass chain x, x.ec(1), x.ec(2), whose primary object x is a class is extended by a predecessor of x called the (instance) prototype of x, so that prototypes can be thought of as negative eigenclasses.

Since terminal objects do not have instance prototypes, each object is a descendant of the inheritance root in (Θ, ). This allows for a prototypal interpretation of inheritance, as known from the JavaScript programming language. As a consequence, under the additional assumption of single inheritance, object membership with prototypes can be implemented in JavaScript, directly leveraging the native prototypal inheritance. Such an implementation is provided in this document.

Finally, the native JavaScript structure, formed by links corresponding to the __proto__, constructor and prototype properties, is described.

Preface

Author
Ondřej Pavlata
Jablonec nad Nisou
Czech Republic
Document date
Initial releaseMarch 12, 2015
Last major release March 12, 2015
Last updateMarch 12, 2015
(see Document history)
Warning
  1. This document has been created without any prepublication review except those made by the author himself.

Table of contents

S1ȷ: Object membership with prototypes

An S1ȷ structure is a structure (Θ, O, ϵ) where
The structure is subject to the following axioms:
(S1ȷ~1) (Θ, ϵ) is an S1ϵ structure that does not have terminal objects.
(S1ȷ~2) Θ.ec. O.   (That is, eigenclasses of (Θ, ϵ) and their descendants are in O.)
(S1ȷ~3) For every object x from the difference O Θ.ec.,
  • (a) x is minimal in inheritance,
  • (b) x has exactly one inheritance parent.
Note that Θ.ec. in (S1ȷ~2) and (S1ȷ~3) can be equivalently written as x.ec. where x is the inheritance root of (Θ, ϵ). For reasons explained below, we will not use the r symbol for x. Instead, we put r = x.ec.

Proposition A:

  1. There is a one-to-one correspondence between S1ȷ structures and S1ϵ structures. For every S1ϵ structure (Θ', ϵ), if Θ and O are subsets of Θ' given by then (Θ, O, ϵ) is an S1ȷ structure. Conversely, every S1ȷ structure (Θ, O, ϵ) is obtained from a uniquely given (up to isomorphism) S1ϵ structure by the above prescription.
  2. Up to isomorphism, the structure (Θ, ϵ) is uniquely given by (O, ϵ). However, the converse is false in general.
  3. The set Θ O.ec forms a closure system in (Θ, ).
  4. The S1ϵ structure (O, …) is a substructure of (Θ, …) with respect to the signature (Θ, .ec, ).
The terminology and notation for (Θ, ϵ) is adapted to that of (O, ϵ) according to the following diagram.
C.ce = Θ O (instance) prototypes
T terminals   = O r.
C classes   = Θ.class
H helix objects   = Θ.he = R.
R reduced helix   = Θ.re
r.ce inheritance root
r class-inheritance root
c metaclass root / instance root
Θ.c = T C C.ce front objects
Θ.pr = T C primary objects
O.ec = Θ Θ.c eigenclasses
c. = Θ.class(2). metaclasses
r.ec(i).϶ r.ec(i). i-th metalevel
In addition to ϵ, , .ec, .ce, . / ., and .ϵ / .϶, the following notation and terminology will be taken from (Θ, ϵ):

Proposition B:

  1. Prototypes are the eigenclass predecessors of classes, Θ O = C.ce. If x equals y.ce for a class y, then we say that x is an (instance) prototype of y.
  2. The relations (.ec) and () commute, i.e.
  3. The .class map is an extension of the class map from (O, ϵ). For a prototype x, x.class equals x.ec.
  4. Each prototype is a direct instance of its class. As a consequence, C = Θ.class.
  5. The maps .class and .ce establish an order isomorphism between (Θ O, ) and (C, ), to and from, respectively. In particular, there is a one-to-one correspondence between instance prototypes and classes.
  6. The maps .class and .ce form a Galois connection between (Θ, ) and (C, ), i.e. for every object x and every class y, In particular, the instance prototype of a class y is the highest instance of y, w.r.t. .
  7. Prototypes form a closure system in (Θ, ) with .class.ce the corresponding closure operator. This way, the .class map is inherited from prototypes.
  8. The set Θ of objects is a disjoint union of (the sets of) terminals, classes, prototypes and eigenclasses,
  9. The class-inheritance root r is the highest class. Its prototype r.ce is the highest object – the inheritance root.
  10. The helix structure (H, ϵ) can be described by the following table:
    Metalevel index  
    0
    >
    1
    >
    2, 3, …
    Nomenclature Prototypes Classes Eigenclasses
    Expression H.class.ce H.class H.ec(2)
    Highest object r.ce r r.ec
    Lowest object c.ce c
  11. Every metalevel has a top. For an object x,
The instance-of relation

Proposition: The instance-of relation in S1ȷ structures satisfies the following conditions:

  1. (a) The instance-of relation equals () (.class). Note that this only possible because each class has a direct instance. This is generally not satisfied in S1ϵ structures.
  2. (b) For an object x and a class y, That is, x is an instance of y iff x is a descendant of the instance prototype of y.
  3. (c) Assume that all classes are at metalevel 1 (so that C is convex in (Θ, )). Then statements (a) and (b) remain valid if is replaced by a suborder ' that is obtained from by removing strict inheritance between classes, i.e. Note that in (Θ, '), every class has c.ce as a single parent.

Note: In JavaScript, the native core structure implements ' instead of . The (b) condition is used for the interpretation of the instanceof operator.

S1ȷ.c: The front structure

An S1ȷ.c structure is a structure (Θ.c, , .class, .ce, r) where Additional notation / terminology is applied:
The structure is subject to the following axioms:
(S1ȷ.c~1) Inheritance, , is a partial order.
(S1ȷ.c~2) The maps .class and .ce form a Galois connection between (Θ.c, ) and (C, ), i.e. for every object x and class y,
  • x.class y   iff   x y.ce.
(S1ȷ.c~3) The .ce map is injective, i.e. different classes have different instance prototype.
(S1ȷ.c~4) Terminals are minimal in inheritance.
(S1ȷ.c~5) Classes and instance prototypes are disjoint sets.
(S1ȷ.c~6) Helix objects satisfy the following properties:
  • (a) The r object is subject to the following:
    • r is a class that is a common ancestor of all classes.
    • r has at least 2 strict ancestors.
    • r has no siblings in .
    As a consequence of (ⅰ), every object is a descendant of r.ce, the inheritance root.
  • (b) Helix objects are linearly ordered by inheritance.
  • (c) The c class is the least (front) helix object.
(S1ȷ.c~7) The set C H.c of non-helix classes forms a down-set in inheritance.
(S1ȷ.c~8) The set C of classes is finite.

Proposition:

  1. An S1ȷ.c structure is uniquely given by any of the following:
  2. The restriction of an S1ȷ structure to the set of front objects (i.e. objects that are not eigenclasses) is an S1ȷ.c structure. That is, if (Θ, O, ϵ, ) is an S1ȷ structure then (Θ.c, ϵ, ) is an S1ȷ.c structure.

Sample A

The following diagram shows the front part of a Ruby-like S1ȷ structure. By Ruby-like we mean that the structure satisfies the following additional restrictions: There are 3 helix classes: (Ruby also contains the Module class between Class and Object.) Blue arrows indicate the class map in the restriction to prototypes. On the remaining objects x, the .class map is inherited: x.class equals y.class where y is the least ancestor of x that is a prototype. (For classes x, y is always equal to c.ce.)
r = BasicObject
c = Class
A = Class.NEW()
B = Class.NEW(A)
s = A.NEW()
u = B.NEW()
v = B.NEW()
The code on the right is a valid Ruby code except that NEW (uppercase) is used instead of new (lowercase). This is because the code is also a valid JavaScript code that uses a NEW method for creating instances (rather than the built-in new operator). The NEW method belongs to the library described in the next section. The library implements creation and introspection of S1ȷ structures with single inheritance.

Implementation in JavaScript

S1ȷ structures with single inheritance can be implemented in JavaScript. This document provides such an implementation, written in proto-class-core.js. Functions defined in this script are evaluated directly in this document, using the jClassy library [] and the jQuery library [] for reporting the results.
Object naming
For simplicity, some hidden magic is performed to report objects by convenient names. In the following code, the class-inheritance root r is reported as r rather than BasicObject. Likewise, user classes and terminals are reported by the names of the local variables that refer to them. For a class x, the instance prototype x.ce is reported as x#. The last line shows that sometimes also Class and Object can be reported as c and o, respectively.

All objects are referred by non-global variables. The Object class is different from the built-in object constructor:

Basic links between objects
A structure (Θ, .sc, .class, .ce), where .sc is the superclass partial map, is implemented via object properties according to the following table:

Note: The $class and $proto properties are created by the library. They are not built-in properties of JavaScript objects.

The following code shows the one-to-one correspondence between classes and instance prototypes. The built-in JavaScript inheritance is used to extend the .class map from prototypes to other objects (classes and terminals). In the sample structure, all classes reside at metalevel 1, so that their class is constantly Class, just like in Ruby. The jQuery utility method $.map is used to report the result of x.class for each object x in a list. For superclass links, the non-standard built-in __proto__ property is used. If not natively supported, the property is explicitly set.

Testing inheritance
The following tests demonstrate name resolution based on inheritance. The flake property is set to some selected objects x and the value of y.flake is reported for some selected descendants y of x.

Sample B

In the second sample structure, we allow classes on higher metalevels (i.e. explicit metaclasses other than c). The metaclasses N and M belong to metalevels 2 and 3, respectively. The diagram shows also the six helix eigenclasses on these metalevels.
r = BasicObject
c = Class
M = Class.NEW(Object.ec(2))
N = M.NEW()
A = N.NEW()
B = N.NEW(A)
s = A.NEW()
u = B.NEW(); v = B.NEW()
The M metaclass is created as a direct descendant of Object.ec(2), the second eigenclass of Object.
Introspection tests
The following code introspects the sample structure using the library in proto-class-core.js. The i-th eigenclass of a primary object x, i > 0, is reported as x^i. Instantiation of a class other than c decreases the metalevel index:

The native core structure of JavaScript

As of ECMAScript, 5th Edition, [] JavaScript provides a limited native support for object membership. Similarly to the user implementation provided above, the native core structure can be expressed as (Ō, .sc', .class, .ce), i.e. it consists of a set Ō of objects together with three families of links between them. This time, the correspondence is as follows:

Notes:

The structure can be obtained as a modification of an S1ȷ.c structure which requires both specialization as well as generalization. Semi-formally, the structure can be described as follows:
(A) Only the front structure is supported, there are no actual eigenclasses.
(B) The structure is Ruby-like, i.e.
  • (1) The inheritance relation is a tree.
  • (2) Every class is on the metalevel 1.   (That is, c is the only metaclass.)
(C) There are exactly 2 helix classes: c = Function < Object = r. (However, this ordering should be interpreted as c.ce < r.ce, see (D) below.)
(D) There is no strict inheritance between classes. The regular inheritance is modified to ' according to (c) in The instance-of relation subsection. In a correspondence, the child-to-parent (partial) map is redefined from .sc to .sc' by
  • x.sc' = c.ce   if x is a class,   (That is, the inheritance parent of x equals Function.prototype.)
  • x.sc' = x.sc   otherwise.
(E) The instance root c can have terminal instances. This relaxation allows to include native built-in functions like eval or parseInt into the structure.
(F) The set C of classes can be strictly larger than Ō.class. The objects from C Ō.class are those created using the standard built-in Function.prototype.bind method. Every class x from C Ō.class shares instances with x.ce.class, the target class to which x is (ultimately) bound.
Sample α
The following sample structure is obtained from the A sample by reducing the number of helix classes and removing strict inheritance between classes so that c.ce becomes the inheritance parent of every class.
r = Object
c = Function
A = new c
B = new c; B.prototype.__proto__ = A.prototype
s = new A
u = new B; v = new B
Sample β
In order to also demonstrate features (E) and (F), the previous sample has been extended by two objects, denoted e and BB.
r = Object
c = Function
e = eval
A = new c
B = new c; B.prototype.__proto__ = A.prototype
s = new A
u = new B
BB = B.bind({})
v = new BB
  • e is a terminal instance of c.
  • BB is a class that does not belong Ō.class.
The instanceof operator
The instance-of relation, ϵ, can be introspected using the instanceof operator. The operator works according to the following prescription: [] Note that the instance prototype y.ce is not considered to be an instance of y so that
Native objects
The set Ō of objects under consideration is assumed to only contain such values x that are native objects or primitive values other than null or undefined. That is, where name is one of "Arguments", "Array", "Boolean", "Date", "Error", "Function", "JSON", "Math", "Number", "Object", "RegExp", or "String". This condition excludes host objects. []

Note: The primitive values x other than null and undefined are such that typeof x is either 'boolean', 'number' or 'string'. Using object wrapping, these values can be considered to be native objects.

Introspection
With limitations, the native core structure can be introspected according to the following correspondence table.
Expression Description
In abstract notation In JavaScript
r.ce Object.prototype The inheritance root
r Object The class-inheritance root
c Function The instance root
x Ō.class x.hasOwnProperty('prototype') x is a class not created using bind
x C.ce x.hasOwnProperty('constructor') x is an instance prototype
x c.϶ typeof x === 'function' x is an instance of c
x.sc' x.__proto__ The inheritance parent of x
x.class x.constructor The class of x
x.ce x.prototype The instance prototype of x Ō.class
x <' y y.isPrototypeOf(Object(x)) x is a strict inheritance descendant of y
x ϵ y and x y.ce Object(x) instanceof y x is an instance of y

Notes:

  1. The variables x and y in the above JavaScript expressions are only allowed to refer to native objects according to the previous subsection.
  2. The instanceof operator as well as the isPrototypeOf method require a wrapper to work with primitive values.
  3. As of ECMAScript, 5th Edition, the inheritance parent of x can be obtained by Object.getPrototypeOf (Object(x)).
  4. Instances of the instance root c can be any of the following: There is no built-in support to distinguish between all these groups in a simple way.
Assumptions
The above description of the JavaScript native core structure (Ō, .sc', .class, .ce) is only valid under ideal circumstances which are not guaranteed by the ECMAScript standard. In particular, the following assumptions are required:
New class creation
The new operator can be uniformly used for the creation of terminal objects as well as of classes. However, classes y created this way are always direct subclasses of Object (that is y.prototype.__proto__ equals Object.prototype). [] As of ECMAScript, 5th Edition, JavaScript does not provide any built-in method for creating classes that are deeper in the hierarchy right after their creation. The position of a class y has to be adjusted by user means in one of the following ways.
Built-in native classes
The following diagram displays the hierarchy of built-in native classes. Green lines show inheritance between instance prototypes of these classes (rather than between classes themselves).

 

References
Ecma International, ECMAScript Language Specification, Edition 5.1, http://www.ecma-international.org/ecma-262/5.1/
David Flanagan, JavaScript: The Definitive Guide, Sixth Edition, O'Reilly 2011
Ondřej Pavlata, Object Membership: The Core Structure of Object Technology, 2012–2015, http://www.atalon.cz/om/object-membership/
Ondřej Pavlata, Object Membership: The Core Structure of Object-Oriented Programming, 2012–2015, http://www.atalon.cz/om/object-membership/oop/
Ondřej Pavlata, jClassy: Class system in JavaScript, http://jclassy.org/
Ondřej Pavlata, jClassy: Comparison with other libraries, http://jclassy.org/doc/co
John Resig & the jQuery team, jQuery, http://jquery.com
Document history
March122015 The initial release.
License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License.