This is an archived page. It's not actively maintained.

IDL interface rules

Original Document Information

For support and discussion:

This document describes some dos and don'ts when writing an interface in IDL for Mozilla. For a complete guide, see the How To Freeze document.

Rule: Use camel case for naming.
All methods and attributes should begin with a lowercase letter. Every subsequent word in the method or attribute name should be capitalized. Avoid capitalizing first letters and using underscores to separate words.
Why: IDL usually follows Java and JavaScript convention, which is camel case.
In addition, the first letter of all names are promoted to upper case in C++. The C++ signature is the same whether or not the first letter is capitalized.
  • Incorrect:
        /* don't capitalize first letters! */
        void OpenFile(in nsIFile file);
        attribute AString Filename;
        /* Avoid underscores! */
        attribute long unknown_entries;
  • Correct:
        void openFile(in nsIFile file);
        attribute AString filename;
        attribute long unknownEntries;
Rule: Use attributes wherever you are referring to a single, non-dynamic value.
Why: Scripted access to the interface is easier to read.
Combining two get/set methods into a single attribute also syntactically shows their relevance. Methods also imply some sort of action or side effect.
  • Incorrect:
        /* These refer to the same value, why make them functions? */
        long getColorValue();
        void setColorValue(in long value);
        /* we just want a getter, but we can still use an attribute!
         * besides, a method implies an action. */
        long brightness();
  • Correct:
        attribute long colorValue;
        readonly attribute long brightness;
Rule: Avoid excessively long names, but keep them readable.
Don't abbreviate words. Avoid names that involve prepositions like "of" or "on"
  • Incorrect:
        /* seems a bit verbose */
        readonly attribute long numberOfEntries;
        /* why shorten this? is this Attribute? Attrition? */
        long getAttrCount(in ACString name);
  • Correct:
        readonly attribute long entryCount;
        long getAttributeCount(in ACString name);
Rule: Use ACString to represent ASCII strings or binary string-like data.
Why: The nsA- string classes are more efficient than the "string" type.
They include the length of the string passed in, and avoid excess allocations. They also allow for subfragments of existing strings without copying, and when assigning one string to another, the underlying buffer can often be shared.
  • Incorrect:
        /* use the new string classes! */
        void processName(in string name);
        /* high bit will get stripped by XPConnect. is that ok? */
        void fillBuffer(in string data);
        /* new string classes will avoid excess allocation,
         * especially when the caller uses nsCAutoString  */
        void getHeaderValues(out string prefix, out string postfix);
  • Correct:
        void processName(in ACString name);
        void fillBuffer(in ACString data);
        void getHeaderValues(out ACString prefix, out ACString postfix);
Rule: Use AString or AUTF8String to represent unicode strings. Avoid the "wstring" type where possible.
Why: XPConnect will properly handle unicode conversion.
In addition, the nsA- string classes are more efficient than the old "wstring" type.
  • Incorrect:
        /* Even if errorMsg is UTF8, it will get corrupted by XPConnect */
        void displayError(in string errorMsg);
        /* use AString to allow fragment to have a length */
        void parseFragment(in wstring fragment);
  • Correct:
        void displayError(in AUTF8String errorMsg);
        void parseFragment(in AString fragment);
Rule: Avoid out parameters
Avoid them especially when a method has only one out parameter. Use the return value of a function instead.
Why: Be script friendly!
out parameters are extra work for scripts, which must create a temporary object to hold the resulting value.
  • Incorrect:
        /* This will be frustrating to call from a script */
        void getHeaderValue(in ACString header, out AString value);
        /* why isn't this just an attribute? */
        void getLinkSource(out AString source);
  • Correct:
        AString getHeaderValue(in ACString header);
        readonly attribute AString linkSource;
Rule: Avoid excess #includes.
Try to avoid #including extra .h or .idl files unless there are constants or other declarations that are required to compile the .idl file.
Why: Excess includes increase dependencies.
A consumer of an interface does not necessarily use the full interface, and thus may not need a full declaration of every type that the interface uses.
  • Incorrect:
        /* Can't compile the idl file without this, we derive from nsISupports */
        #include "nsISupports.idl"
        /* does every consumer need to also include this? */
        #include "nsIAtom.idl"
        /* Need this for definition of PRThreadPriority */
        #include "nsIThread.idl"
        interface nsIFoo : nsISupports {
            void setThreadPriority(in nsIThread thread, in PRThreadPriority pri);
            nsIAtom getThreadAtom(in nsIThread thread);
  • Correct:
        /* Can't compile the idl file without this */
        #include "nsISupports.idl"
        /* Need this for definition of PRThreadPriority */
        #include "nsIThread.idl"
        /* Let consumers #include the right header if they need the full definition. */
        interface nsIAtom;
        interface nsIFoo : nsISupports {
Rule: Try to #include only other .idl files.
If you need access to a type available only in C++, try to predeclare it and rely on C++ consumers to #include the correct header.
Why: Easier maintenance of IDL files.
Generated C headers will differ from the IDL, causing confusion as to what classes have been defined. If you predeclare a type and then #include a .h file in order to get the definition, you may have problems with the generated header if the #included .h file changes later. Excessive #includes can also cause unnecessary rebuilding when a header changes.
  • Incorrect:
        #include "nsIArena.h" /* C++ only header */
        #include "nsIThread.h" /* Available as nsIThread.idl */
        /* now have to predeclare nsIThread since IDL doesn't know about it */
        interface nsIThread;
  • Correct:
        /* If header is available (and we really need it) just #include it */
        #include "nsIThread.idl"
        /* otherwise, predeclare it */
        interface nsIArena;
Rule: Avoid CID and ContractID declarations in IDL or C++ interface declarations
Why: IDL is for declaring interfaces, and interfaces alone. CIDs and ContractIDs are implementation details.
Instead of putting these details in an IDL file, put them in a separate header file. The separate header file could contain all ContractIDs/CIDs for your module, or you could create a single C++ header which contains the ContractID/CID.
  • Incorrect:
        // nsIFoo.idl:
        // ugh! This doesn't belong in IDL!
        #define NS_FOO_CONTRACTID ";1"
  • Correct:
        // nsIFoo.idl contains only true IDL
        // nsFoo.h contains the ContractID declaration:
        #define NS_FOO_CONTRACTID ";1"
  • Author: Alec Flett
  • Last Updated Date: April 27, 2004
  • Copyright Information: Portions of this content are © 1998–2007 by individual contributors; content available under a Creative Commons license | Details.