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
Carbon function:
OSStatus
CreateNewMenu( MenuID menuID,
MenuAttributes menuAttributes,
MenuRef* outMenuRef );
Sets*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 withDisposeMenu. On failure, returns a nonzero error code. Specifically documented error codes includeparamErrandmemFullErr.
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 typen::owned< MenuRef >is astd::auto_ptr-like type associated withDisposeMenu. On failure, exits with an exception. Noteworthy exceptions includeN::OSStatusand its subclassesparamErrandmemFullErr.
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
nucleus::ownedorstd::auto_ptrtypes to indicate transfer of ownership. - The type
Nitrogen::OSStatusrepresents allOSStatuserrors. - For each Carbon
OSStatusvalue, there is a similarly-named subclass ofNitrogen::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]