Interfaces

Interfaces allow Java developers to define an Application Programmer Interface (API) expressing the contract between a class and the users of a class. While JavaScript will not perform the type checking that interfaces in Java provide, it does provide the basic tools necessary to perform what is known as duck typing, the notion that if it walks like a duck an quacks like a duck, for our purpose we can assume it is a duck. JavaScript provides a way to determine if an object has a property. The following code would determine if the object o is a duck.

if ( o.walk && o.quack ) {
    // Congratulations! It's a duck!
}

To be thorough, we should test to see if walk and swim are both functions. That is readily accomplished using the typeof operator.

if ( o.walk && typeof(o.walk) == "function" &&
     o.swim && typeof(o.quack) == "function") {
    // Still a duck!
}

This approach to type checking has several problems. Performing these tests each time we need to know if an object implements a specific interface is not convenient and prone to errors, especially when the interface is complicated or the tests are performed frequently. It does not help us verify that an object implements interfaces that have no methods, such as the Serializable interface in Java. We would prefer to be able to document that a class implements an interface and verify that all methods of the interface are implemented.

To add support for interfaces in our framework, we will provide a way to declare an interface. Here is an example of the interface declaration syntax.

xclass.declareInterface("animal.Swimmer", [ "swim" ]);

We model an interface by creating the XInterface class which stores the name and namespace of an interface and a list of the interface methods.

function XInterface(className, namespace, methods) {
    this.className = className;
    this.namespace = namespace;
    this.methods = methods;
}

XClass is augmented with a declareInterface method for declaring new interfaces. It maps the fully qualified interface name to a simple name and namespace, creates an instance of XInterface, and stores the new interface in the namespace.

declareInterface: function(fullName, methods) {
    var names = fullName.split('.');
    var name = names.pop();
    var namespace = this.namespace(names);
    var newInterface = new XInterface(name, namespace, methods);
    namespace[name] = newInterface;
},

Next we will augment the framework with a way to add interfaces to classes.