CrxOop CrxOop: Bringing Object Oriented Programming, and Proper Prototype Based Programming, To Javascript
The aim of the library documented below is to provide developers with a solution to allow development using interfaces and classes as they are known in other object oriented programming (OOP) languages such as C++, C#, Java and PHP. Further more, V1.4 introduces structures, a generalization of the concept of prototypal inheritance, known here as POBP.
Subject
Body*
Email
SUBMIT CLOSE
Menu

5.4.1 Constructor

Look at Figure 02. The function CONSTRUCT takes an argument indicating the structure name and returns the construction function which is an equivilant to constructors in OOP languages. Please note the following

  • The definition keyword CONSTRUCT is case sensitive even in the verbose syntax.
  • A constructor may not throw an exception. This will cause a fatal error.
  • A constructor may call the constructor of the inherited structure, one level up, but no more. This means, for example, that the constructor of a structure may not call the grand parent struture's constructor
  • A default constructor is created when no constructor is defined. The default constructor is a function that takes no arguments.
  • The structure constructor is called automatically with no arguments if the derived/child class constructor did not call it explicitly.
  • A constructor may not return any thing.

To understand how to control construction order, you need to know the steps of construction. Look at the figure below. Given a structure 'D', which inherits class 'C', which itself inherits structures 'A' and 'B', as an example, construction of an instance of D follows the following steps:

  1. The instance is fully created.
  2. The constructor of the last inheriting structure is called first. In our example, this means the constructor of structre 'D'. This is the opposite of C++, for example, and intuition in general.
  3. After the constructor is called, CrxOop checks whether the constructor of the parent structure has been called. If not, the parent structre constructor is called. In our example, the parent constructor would be structure 'C'. If there is more than one immediate parent, CrxOop checks in the order defined in the structure definition (left to right), and calls the yet to be called constructors in that order.
  4. The process repeats until all constructors are called.
  5. The instance is now locked. This protects from new properties being created on the underlying javascript object.

Consider the following code and output:

Instance Construction
crx_registerStructure("StructureA",
{
   "VERBOSE": 1,
   "public CONSTRUCT": function(pA)
   {
      console.log("CONSTRUCTING StructureA using pA = " + pA);
   }
});
crx_registerStructure("StructureB",
{
   "VERBOSE": 1,
   "public CONSTRUCT": function(pA)
   {
      console.log("CONSTRUCTING StructureB using pA = " + pA);
   }
});
crx_registerStructure("StructureC",
{
   "VERBOSE": 1,
   "inherits": ["StructureA", "StructureB"],
   "public CONSTRUCT": function(pA)
   {
      console.log("CONSTRUCTING StructureC using pA = " + pA);
   }
});
crx_registerStructure("StructureD",
{
   "VERBOSE": 1,
   "inherits": ["StructureC"],
   "public CONSTRUCT": function(pA)
   {
      console.log("CONSTRUCTING StructureD using pA = " + pA);
   }
});
crx_new("StructureD", 5);
CONSTRUCTING StructureD using pA = 5
CONSTRUCTING StructureC using pA = undefined
CONSTRUCTING StructureA using pA = undefined
CONSTRUCTING StructureB using pA = undefined

Let us follow what happened:

  • The instance was fully created.
  • The constructor of StructureD was called with the passed in parameter, 5.
  • After the constructor of StructureD finished executing, CrxOop found that the constructor of StructureC was not called and called it without any parameters.
  • After the constructor of StructureC finished executing, CrxOop found that the constructor of StructureA was not called and called it without any parameters.
  • After the constructor of StructureA finished executing, Crxop went back to StructureC, and found that the constructor of StructureB was not called and called it without any parameters.
  • The new instance is now locked.

If we wanted the constructor of StructureB execute its useful code before that of the constructor of StructureC, we call it as the first line of code in the constructor of StructureC. Changing the code of StructureC to the following:

crx_registerStructure("StructureA",
{

.
.
.

crx_registerStructure("StructureC",
{
   "VERBOSE": 1,
   "inherits": ["StructureA", "StructureB"],
   "public CONSTRUCT": function(pA)
   {
      this.CONSTRUCT("StructureB")(pA);
      console.log("CONSTRUCTING StructureC using pA = " + pA);
   }
});
crx_new("ClassC", 5);
CONSTRUCTING StructureD using pA = 5
CONSTRUCTING StructureB using pA = undefined
CONSTRUCTING StructureC using pA = undefined
CONSTRUCTING StructureA using pA = undefined

Let us follow what happened:

  • The instance was fully created.
  • After the constructor of StructureD finished executing, CrxOop found that the constructor of StructureC was not called and called it without any parameters.
  • The constructor of StructureC was called without any parameters, but it called the constructor of StructureB in its first line of code passing the parameter 'undefined', before its own useful code.
  • The constructor of StructureC resumed executing its useful code.
  • After the constructor of StructureC finished executing, CrxOop found that the constructor of StructureA was not called and called it without any parameters.
  • The new instance is now locked.

One very important thing to notice is that the ancestors of StructureC at the StructureB branch fully finished executing their constructors before StructureC finished its own. This is important because it is sufficient in practice. If you are the developer of StructureC, and you want the second ancestor's constructor to be called first, all you care about is the second ancestor of StructureC, StructureB, and its ancestors to finish doing what they need in their constructors before your class begins executing its constructing code. The order of the construction of your ancestors at the StructureB branch would not matter. If it did, it would have been the worry of the developers of StructureB, and its ancesotrs if it had any.

If we want the parameter to be passed up to the constructor of StructureB, we would have to include an explicit constructor call in the constructor of StructureD.

crx_registerStructure("StructureA",
{

.
.
.

crx_registerStructure("StructureD",
{
   "VERBOSE": 1,
   "inherits": ["StructureC"],
   "public CONSTRUCT": function(pA)
   {
      this.CONSTRUCT("StructureC")(pA);
      console.log("CONSTRUCTING StructureD using pA = " + pA);
   }
});
crx_new("ClassC", 5);
CONSTRUCTING StructureB using pA = 5
CONSTRUCTING StructureC using pA = 5
CONSTRUCTING StructureA using pA = undefined
CONSTRUCTING StructureD using pA = 5