Nitrogen: A C++ Wrapper for Carbon
Foreword by Lisa Lippincott
Nitrogen is a C++ interface to the Macintosh operating system, based on Apple's Carbon interface. It also serves as the exemplar of an economical approach to adapting C libraries to C++. This approach is described in detail in the founding document for Nitrogen, The Nitrogen Manifesto.
In brief, I feel that the common approach of designing C++ classes to express the object-oriented concepts underlying a C library is an approach doomed by its excessive ambition. A great deal of effort must go into designing, documenting, and understanding such a library. In effect, such a library reexamines the problem space of the original C library, and produces a new design suited to C++. Such redesign is expensive, particularly when one considers the cost of documenting the design and the cost to users of learning the new design. And if the C library continues to evolve, the design may need to be rethought.
In contrast, the Nitrogen approach focuses design effort on the difference between the C and C++ libraries. A set of rules expressing the difference are developed, and the C++ library parallels C library, separated uniformly by those rules. This rigid uniformity reduces the need for documentation. For the most part, the C++ library can rely on the documentation for the C library, coupled with meta-documentation: The rules relating the C library to the C++ library are documented, so a programmer who knows the C library can deduce the form of the C++ library.
For example, a fundamental rule in Nitrogen is name reuse: each
Carbon function name in the global namespace is reused in the
Nitrogen namespace for the same purpose. In Carbon, one may
create a menu with
CreateNewMenu; therefore one may also create a menu with
Nitrogen::CreateNewMenu. And both the signature and the semantics of the Nitrogen
function can be inferred from the signature and semantics of the
OSStatus CreateNewMenu( MenuID menuID, MenuAttributes menuAttributes, MenuRef* outMenuRef );
*outMenuRefto a newly created menu with the given ID and attributes. The usual value for the attributes is zero. The caller is responsible for disposing of the menu with
DisposeMenu. On failure, returns a nonzero error code. Specifically documented error codes include
namespace n = nucleus; namespace N = Nitrogen; n::owned< MenuRef > N::CreateNewMenu( N::MenuID menuID, N::MenuAttributes menuAttributes = N::MenuAttributes() );
Returns a newly created menu with the given ID and attributes. The result type
n::owned< MenuRef >is a
std::auto_ptr-like type associated with
DisposeMenu. On failure, exits with an exception. Noteworthy exceptions include
N::OSStatusand its subclasses
This function illustrates several of the most common Nitrogen rules:
- For each Carbon type, there is a identically-named Nitrogen type, with the same intent (though sometimes Nitrogen reuses the Carbon type, as with MenuRef).
- For each Carbon function, there are identically-named Nitrogen functions or function templates, with the same intent.
- Nitrogen function signatures use Nitrogen types.
- Nitrogen functions provide default values for parameters where no ambiguity arises. Nitrogen functions report failure by throwing exceptions.
- Nitrogen functions return their results.
- Nitrogen functions use
std::auto_ptrtypes to indicate transfer of ownership.
- The type
- For each Carbon
OSStatusvalue, there is a similarly-named subclass of
Nitrogen::OSStatus, with the same intent.
[The original document predates the split into separate Nitrogen and Nucleus libraries. This version is updated to match current usage with the Metamage codebase. -- jjuran]