You are currently viewing a snapshot of www.mozilla.org taken on April 21, 2008. Most of this content is highly out of date (some pages haven't been updated since the project began in 1998) and exists for historical purposes only. If there are any pages on this archive site that you think should be added back to www.mozilla.org, please file a bug.




Revising Interfaces

by Alec Flett <alecf@flett.org >
Comments and questions to netscape.public.mozilla.embedding
Status: incomplete, still need to update examples.

This document explains the different ways to update a frozen interface. It describes the scenarios where each method may be appropriate.
Revision of Interfaces Flowchart
These are the methods that will be described here:
The nsIGlobalHistory interface will be used as an example of an object which is implemented by Mozilla. nsIWebProgressListener will be used as an example of an object which a client might implement. Each of the techniques will be applied when extending both interfaces.

nsIGlobalHistory will be extended by adding the capability of hiding a page in history, and setting the title of a page that has been added to history. The following methods will be used in most of the examples:
    void hidePage(in string url);
    void setPageTitle(in string url, in wstring title);

nsIWebProgressListener will be extended by adding one method:
    ????



Extending an existing interface

The simplest way to extend a frozen interface is to create a new interface which inherits from the old interface. The new implementation implements the new interface, which encapsulates the old one. The old and new interfaces have distince IIDs, so callers are able to QueryInterface to either the original interface, or to the new extended one which will have all the methods of the original.

interface nsIGlobalHistory2 : nsIGlobalHistory {
    void hidePage(in string url);
    void setPageTitle(in string url, in wstring title);
};

interface nsIWebProgressListener2 : nsIWebProgressListener {

};

Pros: Transparent support for old callers. New callers can easily use the new interface.
Cons: Does not allow semantics or signature of old interface to change. If old interface is obsoleted, this one must be as well.

Providing a supplemental interface

This technique involves creating a completely seperate interface with little or no reference to the original interface. Callers must QueryInterface to this new interface.

interface nsIGlobalHistory2 : nsISupports {
    void hidePage(in string url);
    void setPageTitle(in string url, in wstring title);
};

Pros: New interface does not depend on old interface, so old interface can later be obsoleted.
Cons: New interface does not inherently share the capabilities of the old interface - callers must QueryInterface betwen old and new interface.


Replacing an existing interface

This method simply declares the old interface obsolete. Future callers to QueryInterface which are looking for the old interface will fail.This interface is most often used when method signatures need to change. In the nsIGlobalHistory example, we will change the addPage() method to take the hidden state of the url and the page title.

interface nsIGlobalHistory2 : nsISupports {
    void addPage(in string url, in boolean hidden, in wstring title);
    boolean isPageVisited(in string url);
};


This method completely replaces the old interface and assumes a new interface ID. Callers who previously called into this interface will probably fail because the old interface and IID are no longer valid.

Pros: No need to support the old interface, no baggage. Allows complete replacement/removal of any methods in the old interface.
Cons: No support for old callers.


Providing an alternate interface

This technique involves creating and implementing a completely new interface but still retaining support for the old interface. Using this technique you will be able to support both old and new callers.

In our example, we will redefine the addPage() method, but leave isPageVisited alone.

interface nsIGlobalHistory2 : nsISupports {
    void addPage(in string url, in boolean hidden);
    void isPageVisited(in string url);
    void setPageTitle(in string url, in wstring title);
}

Note that the old methods, addPage() and isPageVisited() are still around and that their signatures match the old interface. This technique is difficult to implement because of the fact that they match. In order to correctly implement this, you must create an "inner" object which is contained by your old object, which implements the old interface. When a caller QueryInterface's into the old interface, you must hand them back an pointer to this old interface. This is called encapsulation??? in COM.

Pros: support for both old and new interfaces, able to change function signatures.
Cons: difficult to implement, requires "inner' object if any identical methods exist in both objects.