Working With Classes
********************

In Object-Oriented programming, the most common term you are likely to encounter is ``Class''. A class is like a blueprint for creating an object, which is an instance of that class. Classes contain members, which include primarily properties and methods. A property is a value, much like a variable, that a class ``owns''. A method, when comparing with JavaScript, is a function that is ``owned'' by a class. As a consequence, properties and methods are not part of the global scope.

JavaScript does not support classes in the manner traditionally understood by Object-Oriented programmers. This is because JavaScript follows a different model which instead uses prototypes. Using this model, JavaScript supports basic instantiation and inheritance. Rather than instantiating classes, JavaScript instantiates constructors, which are functions. The following example illustrates how you would typically create a class-like object in JavaScript:

    /**
     * Declaring "classes" WITHOUT ease.js
     */

    // our "class"
    var MyClass = function()
    {
        this.prop = 'foobar';
    }

    // a class method
    MyClass.prototype.getProp = function()
    {
        return this.prop;
    };

    // create a new instance of the class and execute doStuff()
    var foo = new MyClass();
    console.log( foo.getProp() ); // outputs "foobar"
Figure: Basic ``Class'' in JavaScript without using ease.js

This gets the job done, but the prototypal paradigm has a number of limitations amongst its incredible flexibility. For Object-Oriented programmers, it's both alien and inadequate. That is not to say that it is not useful. In fact, it is so flexible that an entire Object-Oriented framework was able to be built atop of it.

ease.js aims to address the limitations of the prototype model and provide a familiar environment for Object-Oriented developers. Developers should not have to worry about how classes are implemented in JavaScript (indeed, those details should be encapsulated). You, as a developer, should be concerned with only how to declare and use the classes. If you do not understand what a prototype is, that should be perfectly fine. You shouldn't need to understand it in order to use the library (though, it's always good to understand what a prototype is when working with JavaScript).

In this chapter and those that follow, we will see the limitations that ease.js addresses. We will also see how to declare the classes using both prototypes and ease.js, until such a point where prototypes are no longer adequate.

Defining Classes
================

C = Class( string NAME, Object DFN )
     Define named class C identified by NAME described by DFN.

C = Class( string NAME ).extend( Object DFN )
     Define named class C identified by NAME described by DFN.

C = Class( Object DFN )
     Define anonymous class C as described by DFN.

C = Class.extend( Object DFN  )
     Define anonymous class C as described by DFN.

Class C can be defined in a number of manners, as listed above, provided a definition object DFN containing the class members and options. An optional string NAME may be provided to set an internal identifier for C, which may be used for reflection and error messages. If NAME is omitted, C will be declared anonymous.

Class must be imported (see Including) from easejs.Class; it is not available in the global scope.

Definition Object
-----------------

dfn = { '[KEYWORDS] NAME': VALUE[, ...] }
     Define definition object DFN containing a member identified by NAME, described by optional KEYWORDS with the value of VALUE. The member type is determined by typeof VALUE. Multiple members may be provided in a single definition object.

The definition object DFN has the following properties:

 1. The keys represent the member declaration, which may optionally contain one or more KEYWORDS delimited by spaces. A space must delimit the final keyword and NAME.

      1. KEYWORDS must consist only of recognized tokens, delimited by spaces.

      2. Each token in KEYWORDS must be unique per NAME.

 2. The VALUE represents the member definition, the type of which determines what type of member will be declared.

      1. A VALUE of type function will define a method, which is an invokable member whose context is assigned to the class or class instance depending on KEYWORDS.

      2. All other types of VALUE will define a property - a mutable value equal to VALUE, assigned to a class or instance depending on KEYWORDS.  Properties may be made immutable using KEYWORDS.

      3. Getters/setters may be defined in an ECMAScript 5 or greater environment. Getters/setters must share the same value for KEYWORDS.

 3. NAME must be unique across all members of DFN.

Member Validations
------------------

For any member NAME:

  * KEYWORDS of member NAME may contain only one access modifier (see Access Modifiers).

  * See Member Keywords for KEYWORDS restrictions.

For any member NAME declared as a method, the following must hold true:

  * KEYWORDS of member NAME may not contain override without a super method of the same NAME (see Inheritance).

  * KEYWORDS of member NAME may not contain both static and virtual keywords (see Static Members and Inheritance).

  * KEYWORDS of member NAME may not contain the const keyword.

  * For any member NAME that contains the keyword abstract in KEYWORDS, class C must instead be declared as an AbstractClass (see Abstract Classes).

Discussion
----------

In f:class-js, we saw how one would conventionally declare a class-like object (a prototype) in JavaScript. This method is preferred for many developers, but it is important to recognize that there is a distinct difference between Prototypal and Classical Object-Oriented development models. Prototypes lack many of the conveniences and features that are provided by Classical languages, but they can be emulated with prototypes. As an Object-Oriented developer, you shouldn't concern yourself with how a class is declared in JavaScript. In true OO fashion, that behavior should be encapsulated. With ease.js, it is.

Let's take a look at how to declare that exact same class using ease.js:

    var Class = require( 'easejs' ).Class;

    var MyClass = Class(
    {
        'public prop': 'foobar',

        'public getProp': function()
        {
            return this.prop;
        }
    } );

    // create a new instance of the class and execute doStuff()
    var foo = MyClass();
    console.log( foo.getProp() ); // outputs "foobar"
Figure: Basic anonymous class declaration using ease.js

That should look much more familiar to Object-Oriented developers. There are a couple important notes before we continue evaluating this example:

  * The first thing you will likely notice is our use of the public keyword; this is optional (the default visibility is public); it may be omitted for a more traditional JavaScript feel. We will get more into visibility later on (see Access Modifiers).

  * Unlike f:class-js, we do not use the new keyword in order to instantiate our class. You are more than welcome to use the new keyword if you wish, but it is optional when using ease.js. This is mainly because without this feature, if the keyword is omitted, the constructor is called as a normal function, which could have highly negative consequences. This style of instantiation also has its benefits, which will be discussed later on.

  * ease.js's class module is imported using require() in the above example.  If using ease.js client-side (see Client-Side Include), you can instead use var Class = easejs.Class. From this point on, importing the module will not be included in examples.

The above example declares an anonymous class, which is stored in the variable MYCLASS. By convention, we use CamelCase, with the first letter capital, for class names (and nothing else).

Class Caveats
-------------

ease.js tries to make classes act as in traditional Classical OOP as much as possible, but there are certain limitations, especially when supporting ECMAScript 3. These situations can cause some subtle bugs, so it's important to note and understand them.

Returning Self
..............

Returning this is a common practice for method chaining. (An interface that performs method chaining is less frequently referred to as a ``fluent interface''. This manual does not use that terminology. Note also that method chaining implies that the class has state: consider making your objects immutable instead, which creates code that is easier to reason about.) In the majority of cases, this works fine in ease.js (see also Temporary Classes):

  var Foo = Class( 'Foo',
  {
      'public beginning': function()
      {
          return this;
      },

      'public middle': function()
      {
          return this;
      },

      'public end': function()
      {
          // ...
      }
  } );

  Foo().beginning().middle().end();
Figure: Using this for method chaining

Within the context of the method, this is a reference to the privacy visibility object for that instance (see The Visibility Object). That is---it exposes all of the object's internal state. When it is returned from a method call, ease.js recognizes this and replaces it with a reference to the public visibility object---the object that the rest of the world interacts with.

But what if you produce this in some other context? A callback, for example:

  var Foo = Class( 'Foo',
  {
     'private _foo': 'good',

      'public beginning': function( c )
      {
          // XXX: `this' is the private visibility object
          c( this );
      },

      'public end': function()
      {
          return this._foo;
      }
  } );

  // result: 'bad'
  Foo()
      .beginning( function( self )
      {
          // has access to internal state
          self._foo = 'bad';
      } )
      .end();
Figure: Accidentally revealing internal state via callback

In f:method-this-callback, beginning applies the callback with a reference to what most would believe to be the class instance (which is a reasonable assumption, considering that ease.js usually maintains that facade). Since this is a reference to the private visibility object, the callback has access to all its internal state, and therefore the ability to set _foo.

To solve this problem, use this.__inst, which is a reference to the public visibility object (the same one that ease.js would normally translate to on your behalf):

  var Foo = Class( 'Foo',
  {
     'private _foo': 'good',

      'public beginning': function( c )
      {
          // OK
          c( this.__inst );
      },

      'public end': function()
      {
          return this._foo;
      }
  } );

  // result: 'good'
  Foo()
      .beginning( function( self )
      {
          // sets public property `_foo', since `self' is now the public
          // visibility object
          self._foo = 'bad';
      } )
      .end();
Figure: Providing public visibility object using this.__inst

Anonymous vs. Named Classes
---------------------------

We state that f:class-easejs declared an anyonmous class because the class was not given a name. Rather, it was simply assigned to a variable, which itself has a name. To help keep this idea straight, consider the common act of creating anonymous functions in JavaScript:

    // anonymous
    var myFunc = function() {};

    // named
    function myNamedFunc() {};
Figure: Anonymous functions in JavaScript

If the function itself is not given a name, it is considered to be anonymous, even though it is stored within a variable. Just as the engine has no idea what that function is named, ease.js has no idea what the class is named because it does not have access to the name of the variable to which it was assigned.

Names are not required for classes, but they are recommended. For example, consider what may happen when your class is output in an error message.

    // call non-existent method
    foo.baz();

    // TypeError: Object #<anonymous> has no method 'baz'
Figure: Anonymous classes do not make for useful error messages

If you have more than a couple classes in your software, that error message is not too much help. You are left relying on the stack trace to track down the error. This same output applies to converting a class to a string or viewing it in a debugger. It is simply not helpful. If anything, it is confusing. If you've debugged large JS applications that make liberal use of anonymous functions, you might be able to understand that frustration.

Fortunately, ease.js permits you to declare a named class. A named class is simply a class that is assigned a string for its name, so that error messages, debuggers, etc provide more useful information. There is functionally no difference between named and anonymous classes.

    var MyFoo = Class( 'MyFoo', {} ),
        foo   = MyFoo();

    // call non-existent method
    foo.baz();

    // TypeError: Object #<MyFoo> has no method 'baz'
Figure: Declaring an empty named class

Much better! We now have a useful error message and immediately know which class is causing the issue.

Constructors
------------

ease.js defines object constructors in a manner consistent with many other classical object-oriented languages: a specially named method on the class.

Traditionally, a ``constructor'' in JavaScript is a function intended to initialize a new object when invoked with the new keyword. That function also contains a prototype property that defines the object's prototype. ECMAScript 6, with the introduction of the class keyword, provided a standard constructor method that generates constructor for the prototype.

ease.js was written long before ES6 was ratified.  The implementation it chose is very similar to that of PHP's (see Constructor Implementation), using a __construct method:

    var Foo = Class( 'Foo',
    {
        // may also use `construct`; see below
        __construct: function( name )
        {
            console.log( 'Hello, ' + name + '!' );
        }
    } );

    // instantiate the class, invoking the constructor
    Foo( 'World' );

    // Output:
    // Hello, World!
Figure: Declaring constructors using ease.js

ease.js introduced the constructor method in version 0.2.7 to match the ES6 ``class'' implementation; it is an alias for __construct, and they may be used interchangeably. This method name may also be used prior to ES6.

    // ECMAScript 6 syntax
    let Foo = Class( 'Foo',
    {
        // you may still use __construct if you'd prefer, as shown above
        constructor( name )
        {
            console.log( 'Hello, ' + name + '!' );
        }
    } );

    // instantiate the class, invoking the constructor
    Foo( 'World' );

    // Output:
    // Hello, World!
Figure: Declaring constructors in an ECMAScript 6 style

The constructor is invoked just after the class is instantiated, allowing for necessary initialization tasks before the class can be used. It is good practice to use the constructor only for initialization that is critical to the object's integrity (such as initializing internal state). It is considered poor design for the constructor to have side-effects; that is, the act of instantiating an object should not manipulate global variables or the environment.

The constructor operates exactly how you would expect a constructor to in JavaScript, with one important difference: returning an object in the constructor does not return that object in place of the new class instance.

If you wish to prevent a class from being instantiated, simply throw an exception within the constructor.

    var Foo = Class( 'Foo',
    {
        __construct: function( name )
        {
            throw Error( "Cannot instantiate class Foo" );
        }
    } );
Figure: Prevent class from being instantiated

Constructors are always public; there is no harm in explicitly specifying the keyword, but it's usually omitted for brevity. It is not permitted to make a constructor protected or private (see Access Modifiers).

Constructors are optional, and no constructor is defined by default. (That is, no user-facing constructor is defined by default; ease.js handles plenty of its own internal tasks during construction, which cannot be overridden or inhibited.)

Temporary Classes
-----------------

In f:class-easejs, we saw that the new keyword was unnecessary when instantiating classes. This permits a form of shorthand that is very useful for creating temporary classes, or ``throwaway`` classes which are used only once.

Consider the following example:

    // new instance of anonymous class
    var foo = Class(
    {
        'public bar': function()
        {
            return 'baz';
        }
    } )();

    foo.bar(); // returns 'baz'
Figure: Declaring a temporary (throwaway) class

In f:class-tmp above, rather than declaring a class, storing that in a variable, then instantiating it separately, we are doing it in a single command.  Notice the parenthesis at the end of the statement. This invokes the constructor. Since the new keyword is unnecessary, a new instance of the class is stored in the variable FOO.

We call this a temporary class because it is used only to create a single instance. The class is then never referenced again. Therefore, we needn't even store it - it's throwaway.

The downside of this feature is that it is difficult to notice unless the reader is paying very close attention. There is no keyword to tip them off. Therefore, it is very important to clearly document that you are storing an instance in the variable rather than an actual class definition. If you follow the CamelCase convention for class names, then simply do not capitalize the first letter of the destination variable for the instance.

Temporary Instances
-------------------

Similar to Temporary Classes, you may wish to use an instance temporarily to invoke a method or chain of methods. Temporary instances are instances that are instantiated in order to invoke a method or chain of methods, then are immediately discarded.

    // retrieve the name from an instance of Foo
    var name = Foo().getName();

    // method chaining
    var car = VehicleFactory()
        .createBody()
        .addWheel( 4 )
        .addDoor( 2 )
        .build();

    // temporary class with callback
    HttpRequest( host, port ).get( path, function( data )
    {
        console.log( data );
    } );

    // Conventionally (without ease.js), you'd accomplish the above using
    // the 'new' keyword. You may still do this with ease.js, though it is
    // less clean looking.
    ( new Foo() ).someMethod();
Figure: Declaring a temporary (throwaway) class

Rather than storing the class instance, we are using it simply to invoke methods. The results of those methods are stored in the variable rather than the class instance. The instance is immediately discarded, since it is no longer able to be referenced, and is as such a temporary instance.

In order for method chaining to work, each method must return itself.

This pattern is useful for when a class requires instantiation in order to invoke a method. Classes that intend to be frequently used in this manner should declare static methods so that they may be accessed without the overhead of creating a new class instance.

Inheritance
===========

C' = Class( string NAME ).extend( Object BASE, Object
     DFN ) Define named class C' identified by NAME as a subtype of BASE, described by DFN. BASE may be of type Class or may be any enumerable object.

C' = C.extend( Object DFN )
     Define anonymous class C' as a subtype of class C, described by DFN.

C' = Class.extend( Object BASE, Object DFN )
     Define anonymous class C' as a subtype of BASE, described by DFN. BASE may be of type Class or may be any enumerable object.

C is a class as defined in Defining Classes. BASE may be any class or object containing enumerable members. DFN is to be a definition object as defined in Definition Object.

Provided non-final C or BASE to satisfy requirements of C, class C' will be defined as a subtype (child) of supertype (parent) class C. Provided BASE that does not satisfy requirements of C, C' will be functionally equivalent to a subtype of anonymous class B as defined by B = Class( BASE ).

Member Inheritance
------------------

Let DFN\_N\^C denote a member of DFN in regards to class C that matches (case-sensitive) name N. Let O\_N denote an override, represented as boolean value that is true under the condition that both DFN\_N\^C' and DFN\_N\^C are defined values.

C' will inherit all public and protected members of supertype C such that DFN\_N\^C' = DFN\_N\^C for each DFN\^C. For any positive condition O\_N, member DFN\_N\^C' will be said to override member DFN\_N\^C, provided that overriding member N passes all validation rules associated with the operation. A protected member may be escalated to public, but the reverse is untrue.  private members are invisible to subtypes. (This is true conceptually, but untrue in pre-ES5 environments where ease.js is forced to fall back (see Private Member Dilemma). As such, one should always develop in an ES5 or later environment to ensure visibility restrictions are properly enforced.)

For any positive condition O\_N where member N is defined as a method:

  * One of the following conditions must always be true:

       * DFN\_N\^C is declared with the virtual keyword and DFN\_N\^C' is declared with the override keyword.

            * Note that DFN\_N\^C' will not become virtual by default (unlike languages such as C++); they must be explicitly declared as such.

       * DFN\_N\^C is declared with the abstract keyword and DFN\_N\^C' omits the override keywords.

  * The argument count of method DFN\_N\^C' must be >= the argument count of method DFN\_N\^C to permit polymorphism.

  * A reference to super method DFN\_N\^C will be preserved and assigned to this.__super within context of method DFN\_N\^C'. (Due to an implementation detail, this.__super may remain in scope after invoking a private method; this behavior is undefined and should not be relied on.)

  * A method is said to be concrete when it provides a definition and abstract when it provides only a declaration (see Definition Object).

       * Any method N such that DFN\_N\^C is declared abstract may be overridden by a concrete or abstract method DFN\_N\^C'.

       * A method N may not be declared abstract if DFN\_N\^C is concrete.

  * Member DFN\_N\^C' must be a method.

  * Member DFN\_N\^C must not have been declared private (see Private Member Dilemma).

Members that have been declared static cannot be overridden (see Static Members).

Discussion
----------

Inheritance can be a touchy subject among many Object-Oriented developers due to encapsulation concerns and design considerations over method overrides. The decision of whether or not inheritance is an appropriate choice over composition is left to the developer; ease.js provides the facilities for achieving classical inheritance where it is desired.

Figure: Basic inheritance example

In the above example, we would say that LAZYDOG and TWOLEGGEDDOG are subtypes of DOG, and that DOG is the supertype of the two. We describe inheritance as an ``is a'' relationship. That is:

  * LAZYDOG is a DOG.

  * TWOLEGGEDDOG is also a DOG.

  * DOG is not a LAZYDOG or a TWOLEGGEDDOG.

Subtypes inherit all public and protected members of their supertypes (see Access Modifiers). This means that, in the case of our above example, the walk() and bark() methods would be available to our subtypes.  If the subtype also defines a method of the same name, as was done above, it will override the parent functionality. For now, we will limit our discussion to public members. How would we represent these classes using ease.js?

    // our parent class (supertype)
    var Dog = Class( 'Dog',
    {
        'virtual public walk': function()
        {
            console.log( 'Walking the dog' );
        },

        'public bark': function()
        {
            console.log( 'Woof!' );
        }
    } );

    // subclass (child), as a named class
    var LazyDog = Class( 'LazyDog' ).extend( Dog,
    {
        'override public walk': function()
        {
            console.log( 'Lazy dog refuses to walk.' );
        }
    } );

    // subclass (child), as an anonymous class
    var TwoLeggedDog = Dog.extend(
    {
        'override public walk': function()
        {
            console.log( 'Walking the dog on two feet' );
        }
    } );
Figure: Inheritance in ease.js

You should already understand how to define a class (see Defining Classes).  The above example introduced two means of extending classes -- defining a new class that inherits from a parent:

Named Subclasses
     LAZYDOG is defined as a named subclass (see Anonymous vs. Named Classes). This syntax requires the use of Class( 'Name' ). The extend() method then allows you to extend from an existing class by passing the class reference in as the first argument.

Anonymous Subclasses
     TWOLEGGEDDOG was declared as an anonymous subclass. The syntax for this declaration is a bit more concise, but you forfeit the benefits of named classes (see Anonymous vs. Named Classes). In this case, you can simply call the supertype's extend() method. Alternatively, you can use the Class.extend( Base, {} ) syntax, as was used with the named subclass LAZYDOG.

You are always recommended to use the named syntax when declaring classes in order to provide more useful error messages. If you are willing to deal with the less helpful error messages, feel free to use anonymous classes for their conciseness.

Understanding Member Inheritance
--------------------------------

In f:inheritance, we took a look at how to inherit from a parent class.  What does it mean when we ``inherit'' from a parent? What are we inheriting? The answer is: the API.

There are two types of APIs that subtypes can inherit from their parents:

Public API
     This is the API that is accessible to everyone using your class. It contains all public members. We will be focusing on public members in this chapter.

Protected API
     Protected members make up a protected API, which is an API available to subclasses but not the outside world. This is discussed more in the Access Modifiers section (see Access Modifiers), so we're going to leave this untouched for now.

When a subtype inherits a member from its parent, it acts almost as if that member was defined in the class itself (This statement is not to imply that inheritance is a case of copy-and-paste. There are slight variations, which are discussed in more detail in the Access Modifiers section (see Access Modifiers).). This means that the subtype can use the inherited members as if they were its own (keep in mind that members also include properties). This means that we do not have to redefine the members in order to use them ourselves.

LAZYDOG and TWOLEGGEDDOG both inherit the walk() and bark() methods from the DOG supertype. Using LAZYDOG as an example, let's see what happens when we attempt to use the bark() method inherited from the parent.

    var LazyDog = Class( 'LazyDog' ).extend( Dog,
    {
        /**
         * Bark when we're poked
         */
        'virtual public poke': function()
        {
            this.bark();
        }
    } );

    // poke() a new instance of LazyDog
    LazyDog().poke();

    // Output:
    // Woof!
Figure: Using inherited members

In f:using-inherited-members above, we added a poke() method to our LAZYDOG class. This method will call the bark() method that was inherited from DOG. If we actually run the example, you will notice that the dog does indeed bark, showing that we are able to call our parent's method even though we did not define it ourselves.

Overriding Methods
------------------

When a method is inherited, you have the option of either keeping the parent's implementation or overriding it to provide your own. When you override a method, you replace whatever functionality was defined by the parent. This concept was used to make our LAZYDOG lazy and our TWOLEGGEDDOG walk on two legs in f:inheritance.

After overriding a method, you may still want to invoke the parent's method. This allows you to augment the functionality rather than replacing it entirely.  ease.js provides a magic __super() method to do this. This method is defined only for the overriding methods and calls the parent method that was overridden.

In order to demonstrate this, let's add an additional subtype to our hierarchy.  ANGRYDOG will be a subtype of LAZYDOG. Not only is this dog lazy, but he's rather moody.

    var AngryDog = Class( 'AngryDog' ).extend( LazyDog,
    {
        'public poke': function()
        {
            // augment the parent method
            console.log( 'Grrrrrr...' );

            // call the overridden method
            this.__super();
        }
    } );

    // poke a new AngryDog instance
    AngryDog().poke();

    // Output:
    // Grrrrrr...
    // Woof!
Figure: Using __super() method

If you remember from f:using-inherited-members, we added a poke() method to LAZYDOG. In f:super-method above, we are overriding this method so that ANGRYDOG growls when you poke him. However, we still want to invoke LAZYDOG's default behavior when he's poked, so we also call the __super() method. This will also make ANGRYDOG bark like LAZYDOG.

It is important to note that __super() must be invoked like any other method. That is, if the overridden method requires arguments, you must pass them to __super(). This allows you to modify the argument list before it is sent to the overridden method.

Arbitrary Supertype Method Invocation
.....................................

The aforementioned __super method satisfies invoking an overridden method within the context of the method that is overriding it, but falls short when needing to invoke an overridden method outside of that context.

As an example, consider that AngryDog also implemented a pokeWithDeliciousBone method, in which case we want to bypass the dog's angry tendencies and fall back to behaving like a LazyDog (the supertype). This poses a problem, as we have overridden LazyDog#poke, so calling this.poke would not yield the correct result (the dog would still respond angerly). __super cannot be used, because that would attempt to invoke a supermethod named pokeWithDeliciousBone; no such method even exists, so in this case, __super wouldn't even be defined.

We can remedy this using this.poke.super, which is a strict reference to the overridden poke method (in this case, LazyDog.poke):

    var AngryDog = Class( 'AngryDog' ).extend( LazyDog,
    {
        'public poke': function()
        {
            // ...
        },

        'public pokeWithDeliciousBone': function()
        {
            // invoke LazyDog.poke
            this.poke.super.call( this );
        }
    } );

    // poke a new AngryDog instance with a delicious bone
    AngryDog().pokeWithDeliciousBone();

    // Output:
    // Woof!
Figure: Using the method-supecific super reference

It is important to note that, in its current implementation, since super is a reference to a function, its context must be provided using the ECMAScript-native apply or call (the first argument being the context); using this as the context (as shown above) will invoke the method within the context of the calling instance. (Specifically, it will invoke the method within the context of the calling instance's private visibility object (see The Visibility Object). While this may seem like a bad idea---since it appears to give the supermethod access to our private state---note that the method wrapper for the overridden method will properly restore the private state of the supertype upon invocation.)

Type Checks and Polymorphism
----------------------------

The fact that the API of the parent is inherited is a very important detail. If the API of subtypes is guaranteed to be at least that of the parent, then this means that a function expecting a certain type can also work with any subtypes. This concept is referred to as polymorphism, and is a very powerful aspect of Object-Oriented programming.

Let's consider a dog trainer. A dog trainer can generally train any type of dog (technicalities aside), so it would stand to reason that we would want our dog trainer to be able to train LAZYDOG, ANGRYDOG, TWOLEGGEDDOG, or any other type of DOG that we may throw at him/her.

Figure: Class structure to demonstrate polymorphism

Type checks are traditionally performed in JavaScript using the instanceOf operator. While this can be used in most inheritance cases with ease.js, it is not recommended. Rather, you are encouraged to use ease.js's own methods for determining instance type (The reason for this will become clear in future chapters. ease.js's own methods permit checking for additional types, such as Interfaces.). Support for the instanceOf operator is not guaranteed.

Instead, you have two choices with ease.js:

Class.isInstanceOf( type, instance );
     Returns true if INSTANCE is of type TYPE. Otherwise, returns false.

Class.isA( type, instance );
     Alias for Class.isInstanceOf(). Permits code that may read better depending on circumstance and helps to convey the ``is a'' relationship that inheritance creates.

For example:

    var dog   = Dog()
        lazy  = LazyDog(),
        angry = AngryDog();

    Class.isInstanceOf( Dog, dog ); // true
    Class.isA( Dog, dog );          // true
    Class.isA( LazyDog, dog );      // false
    Class.isA( Dog, lazy );         // true
    Class.isA( Dog, angry );        // true

    // we must check an instance
    Class.isA( Dog, LazyDog ); // false; instance expected, class given
Figure: Using ease.js to determine instance type

It is important to note that, as demonstrated in f:instanceof-ex above, an instance must be passed as a second argument, not a class.

Using this method, we can ensure that the DOGTRAINER may only be used with an instance of DOG. It doesn't matter what instance of DOG - be it a LAZYDOG or otherwise. All that matters is that we are given a DOG.

    var DogTrainer = Class( 'DogTrainer',
    {
        'public __construct': function( dog )
        {
            // ensure that we are given an instance of Dog
            if ( Class.isA( Dog, dog ) === false )
            {
                throw TypeError( "Expected instance of Dog" );
            }
        }
    } );

    // these are all fine
    DogTrainer( Dog() );
    DogTrainer( LazyDog() );
    DogTrainer( AngryDog() );
    DogTrainer( TwoLeggedDog() );

    // this is not fine; we're passing the class itself
    DogTrainer( LazyDog );

    // nor is this fine, as it is not a dog
    DogTrainer( {} );
Figure: Polymorphism in ease.js

It is very important that you use only the API of the type that you are expecting. For example, only LAZYDOG and ANGRYDOG implement a poke() method. It is not a part of DOG's API. Therefore, it should not be used in the DOGTRAINER class. Instead, if you wished to use the poke() method, you should require that an instance of LAZYDOG be passed in, which would also permit ANGRYDOG (since it is a subtype of LAZYDOG).

Currently, it is necessary to perform this type check yourself. In future versions, ease.js will allow for argument type hinting/strict typing, which will automate this check for you.

Visibility Escalation
---------------------

Let A\_N denote a numeric level of visibility for DFN\_N\^C such that the access modifiers (see Access Modifiers) private, protected and public are associated with the values 1, 2 and 3 respectively. Let A' represent A in regards to C' (see Inheritance).

For any member N of DFN, the following must be true:

  * A'\_N >= A\_N.

  * DFN\_N\^C' cannot be redeclared without providing a new definition (VALUE).

Discussion
..........

Visibility escalation is the act of increasing the visibility of a member.  Since private members cannot be inherited, this would then imply that the only act to be considered "escallation" would be increasing the level of visibility from protected to private.

Many follow the convention of prefixing private members with an underscore but leaving omitting such a prefix from protected members. This is to permit visibility escalation without renaming the member. Alternatively, a new member can be defined without the prefix that will simply call the overridden member (although this would then not be considered an escalation, since the member name varies).

In order to increase the visibility, you must override the member; you cannot simply redeclare it, leaving the parent definition in tact. For properties, this has no discernible effect unless the VALUE changes, as you are simply redefining it. For methods, this means that you are overriding the entire VALUE. Therefore, you will either have to provide an alternate implementation or call this.__super() to invoke the original method.

Note that you cannot de-escalate from public to protected; this will result in an error. This ensures that once a class defines an API, subclasses cannot alter it. That API must be forever for all subtypes to ensure that it remains polymorphic.

Let's take a look at an example.

    var Foo = Class(
        {
            'virtual protected canEscalate': 'baz',

            'virtual protected escalateMe': function( arg )
            {
                console.log( 'In escalateMe' );
            },

            'virtual public cannotMakeProtected': function()
            {
            }
        } ),

        SubFoo = Foo.extend(
        {
            /**
             * Escalating a property means redefining it
             */
            'public canEscalate': 'baz',

            /**
             * We can go protected -> public
             */
            'public escalateMe': function( arg )
            {
                // simply call the parent method
                this.__super( arg );
            }
        } );
Figure: Visibility can be escalated

Note that, in the above example, making the public CANNOTMAKEPROTECTED method protected would throw an error.

Error Subtypes
--------------

Extending ECMAScript's built-in ERROR type is a bit cumbersome (to say the least)---it involves not only the traditional prototype chain, but also setting specific properties within the constructor.  Further, different environments support different features (e.g. stack traces and column numbers), and values are relative to the stack frame of the ERROR subtype constructor itself.

With GNU ease.js, error subtyping is transparent:

    var MyError = Class( 'MyError' )
        .extend( Error, {} );

    var e = MyError( 'Foo' );
    e.message;  // Foo
    e.name;     // MyError

    // -- if supported by environment --
    e.stack;         // stack beginning at caller
    e.fileName;      // caller filename
    e.lineNumber;    // caller line number
    e.columnNumber;  // caller column number

    // general case
    throw MyError( 'Foo' );
Figure: Transparent ERROR extending in ease.js

If ease.js detects that you are extending an ERROR object or any of its subtypes, it will handle a number of things for you, depending on environment:

 1. Produce a default constructor method (see Constructors) that assigns the error message to the string passed as the first argument;

 2. Sets the error name to the class name;

 3. Provides a stack trace via STACK, if supported by the environment, stripping itself from the head of the stack; and

 4. Sets any of FILENAME, LINENUMBER, and/or COLUMNNUMBER when supported by the environment.

If a constructor method is provided in the class definition (see Constructors), then it will be invoked immediately after the error object is initialized by the aforementioned default constructor. (The reason that ease.js does not permit overriding the generated constructor is an implementation detail: the generated constructor is not on the supertype, so there is not anything to actually override.  Further, the generated constructor provides a sane default behavior that should be implicit in error classes anyway; that behavior can be overridden simply be re-assigning the values that are assigned for you (e.g. name or line number).)  THIS.__SUPER in that context refers to the constructor of the supertype (as would be expected), not the default error constructor.

ease.js will automatically detect what features are supported by the current environment, and will only set respective values if the environment itself would normally set them.  For example, if ease.js can determine a column number from the stack trace, but the environment does not normally set COLUMNNUMBER on ERROR objects, then neither will ease.js; this leads to predictable and consistent behavior.

ease.js makes its best attempt to strip itself from the head of the stack trace.  To see why this is important, consider the generally recommended way of creating an ERROR subtype in ECMAScript:

    function ErrorSubtype( message )
    {
        var err = new Error();

        this.name         = 'ErrorSubtype';
        this.message      = message || 'Error';
        this.stack        = err.stack;
        this.lineNumber   = err.lineNumber;
        this.columnNumber = err.columnNumber;
        this.fileName     = err.fileName;
    }

    ErrorSubtype.prototype             = new Error();
    ErrorSubtype.prototype.constructor = ErrorSubtype;
Figure: ERROR subtyping in plain ECMAScript 3

Not only is f:ecma-error-extend all boilerplate and messy, but it's not entirely truthful:  To get a stack trace, ERROR is instantiated within the constructor ERRORSUBTYPE; this ensures that the stack trace will actually include the caller.  Unfortunately, it also includes the current frame; the topmost frame in the stack trace will be ERRORSUBTYPE itself.  To make matters worse, all of LINENUMBER, COLUMNUMBER, and FILENAME (if defined) will be set to the stack frame of our constructor, not the caller.

ease.js will set each of those values to represent the caller.  To do so, it parses common stack trace formats.  Should it fail, it simply falls back to the default behavior of including itself in the stack frame.

The end result of all of this is---hopefully---concise ERROR subtypes that actually function as you would expect of an ERROR, without any boilerplate at all.  The ERROR subtypes created with ease.js can be extended like the built-ins, and may extend any of the built-in error types (e.g. TYPEERROR and SYNTAXERROR).

Final Classes
-------------

F = FinalClass( string NAME, Object DFN )
     Define final named class C identified by NAME described by DFN.

F = FinalClass( string NAME ).extend( Object DFN )
     Define final named class C identified by NAME described by DFN.

F = FinalClass( Object DFN )
     Define anonymous final class C as described by DFN.

F = FinalClass.extend( Object DFN  )
     Define anonymous final class C as described by DFN.

Final classes operate exactly as ``normal'' classes do (see Defining Classes), with the exception that they cannot be inherited from.

Static Members
==============

Static members do not require instantiation of the containing class in order to be used, but may also be called by instances. They are attached to the class itself rather than an instance. Static members provide convenience under certain circumstances where class instantiation is unnecessary and permit sharing data between instances of a class. However, static members, when used improperly, can produce poorly designed classes and tightly coupled code that is also difficult to test. Static properties also introduce problems very similar to global variables.

Let us consider an implementation of the factory pattern.  Class BIGBANG will declare two static methods in order to satisfy different means of instantiation: fromBraneCollision() and fromBigCrunch() (for the sake of the example, we're not going to address every theory). Let us also consider that we want to keep track of the number of big bangs in our universe (perhaps to study whether or not a "Big Crunch" could have potentially happened in the past) by incrementing a counter each time a new big bang occurs.  Because we are using a static method, we cannot use a property of an instance in order to store this data. Therefore, we will use a static property of class BIGBANG.

    var BigBang = Class( 'BigBang',
    {
        /**
         * Number of big bangs that has occurred
         * @type {number}
         */
        'private static _count': 0,

        /**
         * String representing the type of big bang
         * @type {string}
         */
        'private _type': '',

        /**
         * Create a new big bang from the collision of two membranes
         *
         * @return  {BraneSet}  the set of branes that collided
         *
         * @return  {BigBang}  new big bang
         */
        'public static fromBraneCollision': function( brane_set )
        {
            // do initialization tasks...

            return BigBang( 'brane', brane_set.getData() );
        },

        /**
         * Create a new big bang following a "Big Crunch"
         *
         * @param  {BigCrunch}  prior crunch
         *
         * @return  {BigBang}  new big bang
         */
        'public static fromBigCrunch': function( crunch )
        {
            // do initialization tasks...

            return BigBang( 'crunch', crunch.getData() );
        },

        /**
         * Returns the total number of big bangs that have occurred
         *
         * @return  {number}  total number of big bangs
         */
        'public static getTotalCount': function()
        {
            return this.$('_count');
        }

        /**
         * Construct a new big bang
         *
         * @param  {string}  type  big bang type
         * @param  {object}  data  initialization data
         *
         * @return  {undefined}
         */
        __construct: function( type, data )
        {
            this._type = type;

            // do complicated stuff with data

            // increment big bang count
            this.__self.$( '_count',
                this.__self.$('count') + 1
            );
        },
    } );

    // create one of each
    var brane_bang  = BigBang.fromBraneCollision( branes ),
        crunch_bang = BigBang.fromBigCrunch( crunch_incident );

    console.log( "Total number of big bangs: %d", BigBang.getTotalCount() );
    // Total number of big bangs: 2
Figure: Static member example using the factory pattern

Due to limitations of pre-ECMAScript 5 implementations, ease.js's static implementation must be broken into two separate parts: properties and methods.

Static Methods
--------------

In f:static-ex, we implemented three static methods: two factory methods, fromBraneCollision() and FromBigCrunch(), and one getter method to retrieve the total number of big bangs, getTotalCount(). These methods are very similar to instance methods we are already used to, with a few important differences:

 1. Static methods are declared with the static keyword.

 2. In the body, this is bound to the class itself, rather than the instance.

 3. Static methods cannot call any non-static methods of the same class without first instantiating it.

The final rule above is not true when the situation is reversed. Non-static methods can call static methods through use of the __SELF object, which is a reference to the class itself. That is, THIS in a static method is the same object as THIS.__SELF in a non-static method. This is demonstrated by getTotalCount()

    this.$('_count')

and __construct().

    this.__self.$('_count')

To help remember __SELF, consider what the name states. A class is a definition used to create an object. The body of a method is a definition, which is defined on the class. Therefore, even though the body of a method may be called in the context of an instance, it is still part of the class. As such, __SELF refers to the class.

Static Properties
-----------------

You have likely noticed by now that static properties are handled a bit differently than both static methods and non-static properties. This difference is due to pre-ECMAScript 5 limitations and is discussed at length in the Static Implementation section.

Static properties are read from and written to using the static accessor method $(). This method name was chosen because the $ prefix is common in scripting languages such as BASH, Perl (for scalars) and PHP. The accessor method accepts two arguments, the second being optional. If only the first argument is provided, the accessor method acts as a getter, as in f:static-ex's getTotalCount():

    return this.$('_count');

If the second argument is provided, it acts as a setter, as in __construct():

    this.__self.$( '_count',
        this.__self.$('count') + 1
    );

Setting undefined values is supported. The delete operator is not supported, as its use is both restricted by the language itself and doesn't make sense to use in this context. As hinted by the example above, the increment and decrement operators (++ and --) are not supported because JavaScript does not permit returning values by reference.

It is important to understand that, currently, the accessor method cannot be omitted. Consider the following example:

    var Foo = Class( 'Foo',
        {
            'public static bar': 'baz',
        },

        SubFoo = Class( 'SubFoo' ).extend( Foo, {} )
    ;

    // correct
    Foo.$( 'bar, 'baz2' );
    Foo.$('bar');               // baz2
    SubFoo.$('bar');            // baz2
    SubFoo.$( 'bar', 'baz3' );
    Foo.$('bar');               // baz3

    // INCORRECT
    Foo.bar = 'baz2';
    Foo.bar;                    // baz2
    SubFoo.bar;                 // undefined
Figure: Static accessor method cannot be omitted

Constants
---------

Constants, in terms of classes, are immutable static properties. This means that, once defined, a constant cannot be modified. Since the value is immutable, it does not make sense to create instances of the property. As such, constant values are implicitly static. This ensures that each instance, as well as any static access, references the exact same value. This is especially important for objects and arrays.

One important difference between other languages, such as PHP, is that ease.js supports the visibility modifiers in conjunction with the const keyword. That is, you can have public, protected and private constants. Constants are public by default, like every other type of member.  This feature permits encapsulating constant values, which is important if you want an immutable value that shouldn't be exposed to the rest of the world (e.g.  a service URL, file path, etc). Consider the following example in which we have a class responsible for reading mount mounts from /etc/fstab:

    Class( 'MountPointIterator',
    {
        'private const _PATH': '/etc/fstab',

        'private _mountPoints': [],

        __construct: function()
        {
            var data = fs.readFileSync( this.$('_PATH') );
            this._parseMountPoints( data );
        },

        // ...
    } );
Figure: Using the const keyword

In the above example, attempting to access the _PATH constant from outside the class would return undefined. Had the constant been declared as public, or had the visibility modifier omitted, it could have been accessed just like any other static property:

    // if PATH were a public constant value
    MountPointIterator.$('PATH');

Any attempts to modify the value of a constant will result in an exception. This will also work in pre-ES5 engines due to use of the static accessor method ($()).

It is important to note that constants prevent the value of the property from being reassigned. It does not prevent modification of the value that is referenced by the property. For example, if we had a constant FOO, which references an object, such that

    'const foo': { a: 'b' }

it is perfectly legal to alter the object:

    MyClass.$('foo').a = 'c';

Abstract Members
================

'abstract [KEYWORDS] NAME': PARAMS
     Declare an abstract method NAME as having PARAMS parameters, having optional additional keywords KEYWORDS.

Abstract members permit declaring an API, deferring the implementation to a subtype. Abstract methods are declared as an array of string parameter names PARAMS.

    // declares abstract method 'connect' expecting the two parameters,
    // 'host' and 'path'
    { 'abstract connect': [ 'host', 'path' ] }

  * Abstract members are defined using the abstract keyword.

       * Except in interfaces (see Interfaces), where the abstract keyword is implicit.

  * Currently, only methods may be declared abstract.

  * The subtype must implement at least the number of parameters declared in PARAMS, but the names needn't match.

       * Each name in PARAMS must be a valid variable name, as satisfied by the regular expression /^[a-z_][a-z0-9_]*$/i.

       * The names are use purely for documentation and are not semantic.

Abstract members may only be a part of one of the following:

Interfaces
----------

I = Interface( string NAME, Object DFN )
     Define named interface I identified by NAME described by DFN.

I = Interface( string NAME ).extend( Object DFN )
     Define named interface I identified by NAME described by DFN.

I = Interface( Object DFN )
     Define anonymous interface I as described by DFN.

I = Interface.extend( Object DFN  )
     Define anonymous interface I as described by DFN.

Interfaces are defined with a syntax much like classes (see Defining Classes) with the following properties:

  * Interface I cannot be instantiated.

  * Every member of DFN of I is implicitly abstract.

       * Consequently, DFN of I may contain only abstract methods.

  * Interfaces may only extend other interfaces (see Inheritance).

Interface must be imported (see Including) from easejs.Interface; it is not available in the global scope.

Implementing Interfaces
.......................

C = Class( NAME ).implement( I\_0[, ...I\_N]
     ).extend( DFN ) Define named class C identified by NAME implementing all interfaces I, described by DFN.

C = Class.implement( I\_0[, ...I\_N ).extend( DFN )
     Define anonymous class C implementing all interfaces I, described by DFN.

Any class C may implement any interface I, inheriting its API. Unlike class inheritance, any class C may implement one or more interfaces.

  * Class C implementing interfaces I will be considered a subtype of every I.

  * Class C must either:

       * Provide a concrete definition for every member of DFN of I,

       * or be declared as an AbstractClass (see Abstract Classes)

            * C may be declared as an AbstractClass while still providing a concrete definition for some of DFN of I.

Discussion
..........

Consider a library that provides a websocket abstraction. Not all environments support web sockets, so an implementation may need to fall back on long polling via AJAX, Flash sockets, etc. If websocket support is available, one would want to use that. Furthermore, an environment may provide its own type of socket that our library does not include support for. Therefore, we would want to provide developers for that environment the ability to define their own type of socket implementation to be used in our library.

This type of abstraction can be solved simply by providing a generic API that any operation on websockets may use. For example, this API may provide connect(), onReceive() and send() operations, among others. We could define this API in a Socket interface:

var Socket = Interface( 'Socket',
{
    'public connect': [ 'host', 'port' ],

    'public send': [ 'data' ],

    'public onReceive': [ 'callback' ],

    'public close': [],
} );
Figure: Defining an interface

We can then provide any number of Socket implementations:

var WebSocket = Class( 'WebSocket' ).implement( Socket ).extend(
    {
        'public connect': function( host, port )
        {
            // ...
        },

        // ...
    } ),

    SomeCustomSocket = Class.implement( Socket ).extend(
    {
        // ...
    } );
Figure f:interface-impl: Implementing an interface

Anything wishing to use sockets can work with this interface polymorphically:

var ChatClient = Class(
{
    'private _socket': null,

    __construct: function( socket )
    {
        // only allow sockets
        if ( !( Class.isA( Socket, socket ) ) )
        {
            throw TypeError( 'Expected socket' );
        }

        this._socket = socket;
    },

    'public sendMessage': function( channel, message )
    {
        this._socket.send( {
            channel: channel,
            message: message,
        } );
    },
} );
Figure: Polymorphism with interfaces

We could now use ChatClient with any of our Socket implementations:

    ChatClient( WebSocket() ).sendMessage( '#lobby', "Sweet! WebSockets!" );
    ChatClient( SomeCustomSocket() )
        .sendMessage( '#lobby', "I can chat too!" );
Figure: Obtaining flexibility via dependency injection

The use of the Socket interface allowed us to create a powerful abstraction that will allow our library to work across any range of systems. The use of an interface allows us to define a common API through which all of our various components may interact without having to worry about the implementation details - something we couldn't worry about even if we tried, due to the fact that we want developers to support whatever environment they are developing for.

Let's make a further consideration. Above, we defined a onReceive() method which accepts a callback to be called when data is received. What if our library wished to use an Event interface as well, which would allow us to do something like some_socket.on( 'receive', function() {} )?

var AnotherSocket = Class.implement( Socket, Event ).extend(
{
    'public connect': // ...

    'public on': // ... part of Event
} );
Figure: Implementing multiple interfaces

Any class may implement any number of interfaces. In the above example, AnotherSocket implemented both Socket and Event, allowing it to be used wherever either type is expected. Let's take a look:

    Class.isA( Socket, AnotherSocket() );  // true
    Class.isA( Event, AnotherSocket() );   // true
Figure: Implementors of interfaces are considered subtypes of each
implemented interface

Interfaces do not suffer from the same problems as multiple inheritance, because we are not providing any sort of implementation that may cause conflicts.

One might then ask - why interfaces instead of abstract classes (see Abstract Classes)? Abstract classes require subclassing, which tightly couples the subtype with its parent. One may also only inherit from a single supertype (see Inheritance), which may cause a problem in our library if we used an abstract class for Socket, but a developer had to inherit from another class and still have that subtype act as a Socket.

Interfaces have no such problem. Implementors are free to use interfaces wherever they wish and use as many as they wish; they needn't worry that they may be unable to use the interface due to inheritance or coupling issues.  However, although interfaces facilitate API reuse, they do not aid in code reuse as abstract classes do (This is a problem that will eventually be solved by the introduction of traits/mixins.).

Abstract Classes
----------------

A = AbstractClass( string NAME, Object DFN )
     Define named abstract class A identified by NAME described by DFN.

A = AbstractClass( string NAME ).extend( Object DFN )
     Define named abstract class A identified by NAME described by DFN.

A = AbstractClass( Object DFN )
     Define anonymous abstract class A as described by DFN.

A = AbstractClass.extend( Object DFN  )
     Define anonymous abstract class A as described by DFN.

Abstract classes are defined with a syntax much like classes (see Defining Classes). They act just as classes do, except with the following additional properties:

  * Abstract class A cannot be instantiated.

  * Abstract class A must contain at least one member of DFN that is explicitly declared as abstract.

  * Abstract classes may extend both concrete and abstract classes

An abstract class must be used if any member of DFN is declared as abstract. This serves as a form of self-documenting code, as it would otherwise not be immediately clear whether or not a class was abstract (one would have to look through every member of DFN to make that determination).

AbstractClass must be imported (see Including) from easejs.AbstractClass; it is not available in the global scope.

Discussion
..........

Abstract classes allow the partial implementation of an API, deferring portions of the implementation to subtypes (see Inheritance). As an example, let's consider an implementation of the Abstract Factory pattern (See Abstract Factory, GoF)) which is responsible for the instantiation and initialization of an object without knowing its concrete type.

Our hypothetical library will be a widget abstraction. For this example, let us consider that we need a system that will work with any number of frameworks, including jQuery UI, Dojo, YUI and others. A particular dialog needs to render a simple Button widget so that the user may click "OK" when they have finished reading. We cannot instantiate the widget from within the dialog itself, as that would tightly couple the chosen widget subsystem (jQuery UI, etc) to the dialog, preventing us from changing it in the future. Alternatively, we could have something akin to a switch statement in order to choose which type of widget to instantiate, but that would drastically inflate maintenance costs should we ever need to add or remove support for other widget system in the future.

We can solve this problem by allowing another object, a WidgetFactory, to perform that instantiation for us. The dialog could accept the factory in its constructor, like so:

Class( 'Dialog',
{
    'private _factory': null,

    __construct: function( factory )
    {
        if ( !( Class.isA( WidgetFactory, factory ) ) )
        {
            throw TypeError( 'Expected WidgetFactory' );
        }

        this._factory = factory;
    },

    'public open': function()
    {
        // before we open the dialog, we need to create and add the widgets
        var btn = this._factory.createButtonWidget( 'btn_ok', "OK" );

        // ...
    },
} );
Figure: Hypothetical use case for our Abstract Factory

We now have some other important considerations. As was previously mentioned, Dialog itself could have determined which widget to instantiate. By using a factory instead, we are moving that logic to the factory, but we are now presented with a similar issue. If we use something like a switch statement to decide what class should be instantiated, we are stuck with modifying the factory each and every time we add or remove support for another widget library.

This is where an abstract class could be of some benefit. Let's consider the above call to createButtonWidget(), which accepted two arguments: an id for the generated DOM element and a label for the button. Clearly, there is some common initialization logic that can occur between each of the widgets. However, we do not want to muddy the factory up with log to determine what widget can be instantiated. The solution is to define the common logic, but defer the actual instantiation of the Widget to subtypes:

AbstractClass( 'WidgetFactory',
{
    'public createButtonWidget': function( id, label )
    {
        // note that this is a call to an abstract method; the
        // implementation is not yet defined
        var widget = this.getNewButtonWidget();

        // perform common initialization tasks
        widget.setId( id );
        widget.setLabel( label );

        // return the completed widget
        return widget;
    },

    // declared with an empty array because it has no parameters
    'abstract protected getNewButtonWidget': [],
} );
Figure: Defining our Abstract Factory

As demonstrated in f:abstract-factory-define above, we can see a very interesting aspect of abstract classes: we are making a call to a method that is not yet defined (getNewButtonWidget() (Note that we declared this method as protected in order to encapsulate which the widget creation logic (see Access Modifiers Discussion). Users of the class should not be concerned with how we accomplish our job. Indeed, they should be concerned only with the fact that we save them the trouble of determining which classes need to be instantiated by providing them with a convenient API.)). Instead, by declaring it abstract, we are stating that we want to call this method, but it is up to a subtype to actually define it. It is for this reason that abstract classes cannot be instantiated - they cannot be used until each of the abstract methods have a defined implementation.

We can now define a concrete widget factory (see Inheritance) for each of the available widget libraries (Of course, the Widget itself would be its own abstraction, which may be best accomplished by the Adapter pattern.):

Class( 'JqueryUiWidgetFactory' )
    .extend( WidgetFactory,
{
    // concrete method
    'protected getNewButtonWidget': function()
    {
        // ...
    },
} );

Class( 'DojoWidgetFactory' )
    .extend( WidgetFactory,
{
    // ...
} );

// ...
Figure: Defining our concrete factories

With that, we have solved our problem. Rather than using a simple switch statement, we opted for a polymorphic solution:

    // we can use whatever widget library we wish by injecting it into
    // Dialog
    Dialog( JqueryUiWidgetFactory() ).show();
    Dialog( DojoWidgetFactory() ).show();
    Dialog( YuiWidgetFactory() ).show();
Figure: Using our abstract factory WidgetFactory via dependency
injection

Now, adding or removing libraries is as simple as defining or removing a WidgetFactory class.

Another noteworthy mention is that this solution could have just as easily used an interface instead of an abstract class (see Interfaces). The reason we opted for an abstract class in this scenario is due to code reuse (the common initialization code), but in doing so, we have tightly coupled each subtype with the supertype WidgetFactory. There are a number of trade-offs with each implementation; choose the one that best fits your particular problem.

Method Proxies
==============

'proxy [KEYWORDS] NAME': DESTMEMBER
     Declare a proxy method NAME, having optional additional keywords KEYWORDS, that invokes a method of the same name on object DESTMEMBER and returns its result.

Method proxies help to eliminate boilerplate code for calling methods on an encapsulated object---a task that is very common with proxy and decorator design patterns.

var Pidgin = Class( 'Pidgin',
{
    'private _name': 'Flutter',

    'public cheep': function( chirp )
    {
        return this._name + ": cheep " + chirp;
    }

    'public rename': function( name )
    {
        this._name = ''+name;
        return this;
    }
} );

var IratePidginCheep = Class( 'IratePidginCheep',
{
    'private _pidgin': null,

    __construct: function( pidgin )
    {
        this._pidgin = pidgin;
    }

    // add our own method
    'public irateCheep': function( chirp )
    {
        return this._pidgin.cheep( chirp ).toUpperCase();
    },

    // retain original methods
    'proxy cheep':  '_pidgin',
    'proxy rename': '_pidgin',
} );

var irate = IratePidginCheep( Pidgin() );

irate.cheep( 'chirp' );
// "Flutter: cheep chirp"
irate.setName( 'Butter' ).cheep( 'chirp' );
// "Butter: cheep chirp"
irate.irateCheep( 'chop' );
// "BUTTER: CHEEP CHOP"
Figure: Using the proxy keyword to proxy cheep and
rename method calls to the object stored in property _pidgin.

Consider some object O whoose class uses method proxies.

  * All arguments of proxy method O.name are forwarded to destmember.name untouched.

  * The return value provided by destmember.name is returned to the caller of O.name untouched, except that

       * If destmember.name returns destmember (that is, returns this), it will be replaced with O; this ensures that destmember remains encapsulated and preserves method chaining.

  * If destmember is not an object, calls to O.name will immediately fail in error.

  * If destmember.name is not a function, calls to O.name will immediately fail in error.

  * N.B.: Static method proxies are not yet supported.