Next: Static Members, Previous: Defining Classes, Up: Classes [Contents]
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.3
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 theoverride
keyword.- Note that dfn\_n\^C’ will not become
virtual
by default (unlike languages such as C++); they must be explicitly declared as such.
- Note that dfn\_n\^C’ will not become
- dfn\_n\^C is declared with the
abstract
keyword and dfn\_n\^C’ omits theoverride
keywords.
- dfn\_n\^C is declared with the
- 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’.4
- 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.
- Any method n such that dfn\_n\^C is declared
- 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).
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.
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' ); } } );
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: | How to work with inherited members | |
• Overriding Methods: | Overriding inherited methods | |
• Type Checks and Polymorphism: | Substituting similar classes for one-another | |
• Visibility Escalation: | Increasing visibility of inherited members | |
• Error Subtypes: | Transparent Error subtyping | |
• Final Classes: | Classes that cannot be inherited from |
Footnotes
(3)
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.
(4)
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.
Next: Static Members, Previous: Defining Classes, Up: Classes [Contents]