Next: , Previous: Defining Classes, Up: Classes


2.2 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 ).

2.2.1 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.1

For any positive condition o\_n where member n is defined as a method:

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

2.2.2 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.

img/inheritance-ex.png

Figure 2.10: 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:

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 2.11: 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.


Footnotes

[1] 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.