blob: 10f182a76063a962a862cc7517e2c0518478298c [file] [log] [blame]
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
<meta
http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<meta
name="GENERATOR"
content="Mozilla/4.5 [en] (Win98; I) [Netscape]">
<meta
name="Author"
content="Jim des Rivières">
<title>API Rules of Engagement</title>
<link
rel="stylesheet"
href="sources/formate.css">
</head>
<body>
<center>
<h1>How to Use the Eclipse API</h1>
</center>
<blockquote><b>Summary</b> <br>
The Eclipse Platform offers a comprehensive API (Application Programmer
Interface) to developers writing plug-ins. This article discusses the
general ground rules for using the Eclipse Platform API, including how
to tell API from non-API, and how to stay in the API "sweet spot" to
avoid the risk of being broken as the platform and its APIs evolve.
These general ground rules are also recommended practice for plug-ins
that must declare API elements of their own.
<p><b>By Jim des Rivi&egrave;res, OTI</b></p>
<hr WIDTH="100%">
<h3>What it means to be API</h3>
The Eclipse platform defines API elements for use by its clients, namely
ISVs writing plug-ins. These plug-ins may in turn define API elements
for their clients, and so on. API elements are the public face: they
carry a specification about what they are supposed to do, and about how
they are intended to be used. API elements are supported: the Eclipse
platform team will fix implementation bugs where there is a deviation
from the specified behavior. Since there is often a high cost associated
with breaking API changes, the Eclipse platform team will also try to
evolve API elements gracefully through successive major releases.
<h3>How to tell API from non-API</h3>
By their very nature, API elements are documented and have a
specification, in contrast to non-API elements which are internal
implementation details usually without published documentation or
specifications. So if you cannot find the documentation for something,
that's usually a good indicator that it's not API.
<p>To try to draw the line more starkly, the code base for the platform
is separated into API and non-API packages, with all API elements being
declared in designated API packages.</p>
<ul>
<li><b>API package</b> - a Java&trade; package that contains at least
one API class or API interface. The names of API packages are
advertised in the documentation for that component; where feasible,
all other packages containing only implementation details have
"internal" in the package name. The names of API packages may
legitimately appear in client code. For the Eclipse platform proper,
these are:</li>
<ul>
<li><tt>org.eclipse.foo.*</tt> - for example, <tt>org.eclipse.swt.widgets</tt>,
<tt>org.eclipse.ui</tt>, or <tt>org.eclipse.core.runtime</tt></li>
<li><tt>org.eclipse.foo.internal.*</tt> - not API; internal
implementation packages</li>
<li><tt>org.eclipse.foo.examples.*</tt> - not API; these are
examples</li>
<li><tt>org.eclipse.foo.tests.*</tt> - not API; these are test
suites</li>
</ul>
<li><b>API class or interface</b> - a <tt>public</tt> class or
interface in an API package, or a <tt>public</tt> or <tt>protected</tt>
class or interface member declared in, or inherited by, some other API
class or interface. The names of API classes and interfaces may
legitimately appear in client code.</li>
<li><b>API method or constructor</b> - a <tt>public</tt> or <tt>protected</tt>
method or constructor either declared in, or inherited by, an API
class or interface. The names of API methods may legitimately appear
in client code.</li>
<li><b>API field</b> - a <tt>public</tt> or <tt>protected</tt> field
either declared in, or inherited by, an API class or interface. The
names of API fields may legitimately appear in client code.</li>
</ul>
Everything else is considered internal implementation detail and off
limits to all clients. Legitimate client code must never reference the
names of non-API elements (not even using Java reflection). In some
cases, the Java language's name accessibility rules are used to disallow
illegal references. However, there are many cases where this is simply
not possible. Observing this one simple rule avoids the problem
completely:
<ul>
<li><b>Stick to officially documented APIs. </b>Only reference
packages that are documented in the <b><i>published API Javadoc</i></b>
for the component. Never reference a package belonging to another
component that has "internal" in its name---these are never API. Never
reference a package for which there is no published API
Javadoc---these are not API either.</li>
</ul>
<h3>General Rules</h3>
The specification of API elements is generated from Javadoc comments in
the element's Java source code. For some types of elements, the
specification is in the form of a contract. For example, in the case of
methods, the contract is between two parties, the caller of the method
and the implementor of the method. The fundamental ground rule is:
<ul>
<li><b>Honor all contracts.</b> The contracts are described in the
published Javadoc for the API elements you are using.</li>
</ul>
The term "must", when used in an API contract, means that it is
incumbent on the party to ensure that the condition would always be met;
any failure to do so would be considered a programming error with
unspecified (and perhaps unpredictable) consequences.
<ul>
<li><b>You must honor "must". </b>Pay especially close heed to
conditions where "must" is used.</li>
</ul>
Other common sense rules:
<ul>
<li><b>Do not rely on incidental behavior. </b>Incidental behavior is
behavior observed by experiment or in practice, but which is not
guaranteed by any API specification.</li>
<li><b>Do not treat null as an object.</b> Null is more the lack of an
object. Assume everything is non-null unless the API specification
says otherwise.</li>
<li><b>Do not try to cheat with Java reflection.</b> Using Java
reflection to circumvent Java compiler checking buys you nothing more.
There are no additional API contracts for uses of reflection;
reflection simply increases the likelihood of relying on unspecified
behavior and internal implementation detail.</li>
<li><b>Use your own packages. </b>Do not declare code in a package
belonging to another component. Always declare your own code in your
own packages.</li>
</ul>
<h3>Calling public API methods</h3>
For most clients, the bulk of the Eclipse API takes the form of public
methods on API interfaces or classes, provided for the client to call
when appropriate.
<ul>
<li><b>Ensure preconditions.</b> Do ensure that an API method's
preconditions are met before calling the method. Conversely, the
caller may safely assume that the method's postconditions will have
been achieved immediately upon return from the call.</li>
<li><b>Null parameters.</b> Do not pass null as a parameter to an API
method unless the parameter is explicitly documented as allowing null.
This is perhaps the most frequently made programming error.</li>
<li><b>Restricted callers.</b> Do not call an API method that is
documented as available only to certain callers unless you're one of
them. In some situations, methods need to be part of the public API
for the benefit of a certain class of callers (often internal);
calling one of these methods at the wrong time has unspecified (and
perhaps unpredictable) consequences.</li>
<li><b>Debugging methods.</b> Do not call an API method labelled "for
debugging purposes only". For example, most <tt>toString()</tt>
methods are in this category.</li>
<li><b>Parameter capture.</b> Do not pass an array, collection, or
other mutable object as a parameter to an API method and then modify
the object passed in. This is just asking for trouble.</li>
</ul>
<h3>Instantiating platform API classes</h3>
Not all concrete API classes are intended to be instantiated by just
anyone. API classes have an instantiation contract indicating the terms
under which instances may be created. The contract may also cover things
like residual initialization responsibilities (for example, configuring
a certain property before the instance is fully active) and associated
lifecycle responsibilities (for example, calling <tt>dispose()</tt> to
free up OS resources hung on to by the instance). Classes that are
designed to be instantiated by clients are explicitly flagged in the
Javadoc class comment (with words like "Clients may instantiate.").
<ul>
<li><b>Restricted instantiators.</b> Do not instantiate an API class
that is documented as available only to certain parties unless you're
one of them. In some situations, classes need to be part of the public
API for the benefit of a certain party (often internal); instantiating
one of these classes incorrectly has unspecified (and perhaps
unpredictable) consequences.</li>
</ul>
<h3>Subclassing platform API classes</h3>
Only a subset of the API classes were designed to be subclassed. API
classes have a subclass contract indicating the terms under which
subclasses may be declared. This contract also covers initialization
responsibilities and lifecycle responsibilities. Classes that are
designed to be subclassed by clients are explicitly flagged in the
Javadoc class comment (with words like "Clients may subclass.").
<ul>
<li><b>Restricted subclassers.</b> Do not subclass an API class that
is not intended to be subclassed. Treat these classes as if they had
been declared final. (These are sometimes referred to as "soft final"
classes).</li>
</ul>
<h3>Calling protected API methods</h3>
Calling inherited protected and public methods from within a subclass is
generally allowed; however, this often requires more care to correctly
call than to call public methods from outside the hierarchy.
<h3>Overriding API methods</h3>
Only a subset of the public and protected API methods were designed to
be overridden. Each API method has a subclass contract indicating the
terms under which a subclass may override it. By default, overriding is
not permitted. It is important to check the subclass contract on the
actual method implementation being overridden; the terms of subclass
contracts are not automatically passed along when that method is
overridden.
<ul>
<li><b>Do not override a public or protected API method unless it is
explicitly allowed.</b> Unless otherwise indicated, treat all methods
as if they had been declared final. (These are sometimes known as
"soft final" methods). If the kind of overriding allowed is:</li>
<ul>
"
<b>implement</b>
" - the abstract method declared on the subclass must be implemented
by a concrete subclass
<br>
"
<b>extend</b>
" - the method declared on the subclass must invoke the method on
the superclass (exactly once)
<br>
"
<b>re-implement</b>
" - the method declared on the subclass must not invoke the method
on the superclass
<br>
"
<b>override</b>
" - the method declared on the subclass is free to invoke the method
on the superclass as it sees fit
</ul>
<li><b>Ensure postconditions. </b>Do ensure that any postconditions
specified for the API method are met by the implementation upon
return.</li>
<li><b>Proactively check preconditions. </b>Do not presume that
preconditions specified for the API method have necessarily been met
upon entry. Although the method implementation would be within its
rights to not check specified preconditions, it is usually a good idea
to check preconditions (when feasible and reasonably inexpensive) in
order to blow the whistle on misbehaving callers.</li>
<li><b>Null result. </b>Do not return null as a result from an API
method unless the result is explicitly documented (on the specifying
interface or superclass) as allowing null.</li>
<li><b>Return copies. </b>Do not return an irreplaceable array,
collection, or other mutable object as the result from an API method.
Always return a copy to avoid trouble from callers that might modify
the object.</li>
</ul>
<h3>Implementing platform API interfaces</h3>
Only a subset of the API interfaces were designed to be implemented by
clients. API interfaces have a contract indicating the terms under which
it may be implemented. Interfaces that are designed to be implemented by
clients are explicitly flagged in the Javadoc class comment (with words
like "Clients may implement."). A client may declare a subinterface of
an API interface if and only if they are allowed to implement it.
<ul>
<li><b>Restricted implementors.</b> Do not implement an API interface
that is documented as available only to certain parties unless you're
one of them. In many situations, interfaces are used to hide internal
implementation details from view.</li>
</ul>
<h3>Implementing public API methods</h3>
See "Overriding API methods".
<h3>Accessing Fields in API classes and interfaces</h3>
Clients may read API fields, most of which are final. Certain
struct-like objects may have non-final public fields, which clients may
read and write unless otherwise indicated.
<ul>
<li><b>Null fields.</b> Do not set an API field to null unless this is
explicitly allowed.</li>
</ul>
<h3>Casting Objects of a known API type</h3>
An object of a known API type may only be cast to a different API type
(or conditionally cast using instanceof) if this is explicitly allowed
in the API.
<ul>
<li><b>Cast and instanceof.</b> Do not use instanceof and cast
expressions to increase what is known about an object beyond what the
API supports. Improper use exposes incidental implementation details
not guaranteed by the API.</li>
</ul>
And, of course, casting any object to a non-API class or interface is
always inappropriate.
<h3>Not Following the Rules</h3>
Whether done knowingly or unwittingly, there are consequences for
transgressing the rules. It might be easier for all involved if there
were API police that would bust you for breaking the rules. However,
that is not the case. For the most part, API conformance operates as an
honor system, with each client responsible for knowing the rules and
adhering to them.
<p>The contracts on the API elements delimit the behavior that is
supported and sustained. As the Eclipse platform matures and evolves, it
will be the API contracts that guide how this evolution happens. Outside
of these contracts, everything is unsupported and subject to change,
without notice, and at any time (even mid-release or between different
OS platforms). Client code that oversteps the above rules might fail on
different versions and patch levels of the platform; or when run on
different underlying OSes; or when run with a different mix of
co-resident plug-ins; or when run with a different workbench
perspective; and so on. Indeed, no one is even particularly interested
in speculating exactly how any particular transgression might come back
to bite you. To those who choose to ignore the rules, don't say that you
weren't warned. And don't expect much more than a sympathetic "Told you
so."</p>
<p>On the other hand, client plug-in code that lives by the above rules
should continue to work across different versions and patch levels of
the platform, across different underlying OSes, and should peacefully
co-exist with other plug-ins. If everyone plays by the rules, the
Eclipse platform will provide a stable and supported base on which to
build exciting new products.</p>
<p><small>Java and all Java-based trademarks and logos are trademarks or
registered trademarks of Sun Microsystems, Inc. in the United States,
other countries, or both.</small></p>
</blockquote>
</body>
</html>