At an early stage in the Pegasus project it was decided to define all
interface types in the system in an
interface definition language which came to be known as Middl. While
aiding system development this has another benefit: it naturally leads
to a model
of programming where an invocation across an interface passes a
reference to the interface as an argument. The interface structure in
memory contains a reference to state unavailable to the client. This
state together with the other arguments to the call constitute the
complete calling environment. This device is known as a closure. The
style of programming is known as object-based.

Figure: Interface data structures

A closure is a pair of pointers; one points to some state record, the
other to a method table within a module (see figure ).
Since interfaces are typed, the format of
the method table can be derived from the interface type specification.
The state record is opaque to any client of the interface; it is only
manipulated by code within the module. Any call across an interface
adheres to a particular calling
convention, and must pass the closure as the first argument. Thus
the complete environment for the call is passed as arguments.

This technique solves the problem of identifying the calling
environment: it is the state in registers and that accessible on the call
stack or via pointers contained therein. All mutable state in a domain
is encapsulated behind interfaces instantiated at runtime. In some
ways our system is similar to Opal ([]), although
the use of Middl allows a rather more flexible computational model
(for example, we can have multiple interfaces attached to object state,
efficient cross-module exception handling, and a cleaner syntax for
multiple return values).
Nemesis is also a native operating system, rather than one running
over another operating system such as Mach.

Writing programs in this manner is not terribly alien; closures are
after all the mechanism used by many object-oriented languages. As a
result, the performance penalty due to the indirection involved is no
more than virtual function lookup in C++, for example.

By making closures explicit we gain modularity in the system and at
the same time do away with the many of the problems of addressing
state in the system. We can share code at a fine level of granularity
and freely pass real pointers between components of the system with
compile-time type checking.

At a pinch, we can support existing UNIX-oriented C and C++ programs
in the same way that other operating systems do: by linking the program
with a set of stub functions with interfaces to our libraries and running the
whole thing in a single call environment.