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*outMenuRef
to 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 includeparamErr
andmemFullErr
.
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::OSStatus
and its subclassesparamErr
andmemFullErr
.
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::owned
orstd::auto_ptr
types to indicate transfer of ownership. - The type
Nitrogen::OSStatus
represents allOSStatus
errors. - For each Carbon
OSStatus
value, 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]