Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Design

The InterLanguage Unification System


Dr. Dobb's Sourcebook January/February 1997: The InterLanguage Unification System

Tom, a contributing editor for Dr. Dobb's Journal, can be contacted at [email protected].


The InterLanguage Unification System (ILU) was designed at Xerox PARC with the purpose of providing a coherent model for distributing applications and components across machine and network boundaries. The result is a system that hides the details of execution environment from the application at large -- only those components that actually need to interact with the local machine are aware of machine type, operating system, and local resources. Since one of the goals of ILU was to avoid inventing radical new technology, Xerox PARC researchers used existing protocols and methods. The result is a system that standardizes issues such as memory management, error detection, and recovery.

ILU 1.8 includes language support for C++, ANSI C, Modula-3, Common Lisp, and Python. It has been installed in a variety of UNIX implementations, including SPARC workstations under SunOS 4.1.3 and Solaris 2, SGI MIPS running IRIX 5.2, 486 PCs running Linux 1.1.78, DEC Alpha OSF/1, IBM RS/6000 AIX, and HP's HP/UX. An ILU port to Windows 3.1/NT will be made publicly available with ILU 2.0. ILU also supports use of the OMG's CORBA Interface Description Language (IDL). The ILU system is freely available at ftp://ftp.parc.xerox.com/ pub/ilu/ilu.html.

As of this writing, ILU 2.0 is in alpha stage. However, the final version of Release 2.0 will provide enhancements (and some incompatibilities) that deserve mention. All in all, 2.0 will be largely API-compatible with 1.8, which means that ILU code shouldn't require much change. Changes in version 2.0 include:

  • Configuration via GNU autoconf and imake to make UNIX-based installation/configuration easier.
  • Support for C/C++ under Windows 3.1/95/NT. Both Windows binaries and source code will be available.
  • Support for cross-language calls within the same address space.
  • Message protection -- caller/server identity authentication, message-integrity checks, and message encryption -- at the transport level, using message-security protocols such as Netscape's SSL and Microsoft's PCT.
  • A reorganized "transport" abstraction that makes it easier to introduce filters at the transport level.
  • "Simple binding" via shared files or the IP multicast protocol.
  • Support for the OMG's Internet Inter-Orb Protocol (IIOP), which will allow ILU to communicate with other object-request-broker systems such as Sun's NEO, Iona's Orbix, and IBM's DSOM.

The best sources for more information on ILU are the mailing lists at ILU.parc@ xerox.com/ (for general questions; to be added or deleted, send requests to ILU-request.parc@ xerox.com and ILU-interest.parc@ xerox.com).

A Walk Through the ILU System

ILU is mostly about defining interfaces. Hiding behind this simple statement, however, is a powerful programming model that allows the system to provide collections of program units (called modules in ILU terminology). This concentration on the interface between modules allows a module to be written in any language for which ILU provides a binding.

Modules can be written in different application languages, can exist on separate machines, or can be distributed systems implemented by many program instances on many machines. (A program instance is a collection of modules running within a single memory space.)

ILU accomplishes this independence by providing a method for specifying object-oriented interfaces for each module within the system. This interface tells the world about object types, other type information, what exceptions are raised, constants expected, and so on. The mechanism used to accomplish this is a language-neutral Interface Specification Language (ISL).

The ISL is used to define the interface to each module in the system. Types and exceptions are defined and exported functions are specified by defining methods on object types. Tools provided in the ILU software are then run against the definitions to produce stubs for one or more of the languages supported by ILU. These stubs can bind to, call, and be called from other stubs (as long as those stubs are generated from stubs produced for other languages from the same definition). The stub is then linked with the application code, some language-specific code that contains the necessary ILU run-time support for the target language, and the ILU kernel library. The kernel library is written in ANSI C. Table 1 lists ISL reserved words that, when enclosed in double quotes, can be used as identifiers.

ILU Objects

ILU is object oriented. Object types are the first class encapsulation mechanism within ILU. Module functionality is exported as a set of methods that can be invoked on an instance of an object type, in contrast to the procedural programming model of invoking procedures or subroutines. The object instance provides the context for executing methods. The object type system provides limited inheritance to aid in the structuring of interfaces.

A module is a server if it supplies the methods of an object. It is a client if it invokes an object's methods without implementing the methods within the object. Any module may be a client of an object and also provide services for other modules. In ILU, objects can be passed as a parameter to, and returned as a result from, a method call. An object can also be a parameter to an exception.

With any given language-specific set of ILU objects, there is one true object. The true object's methods are actually written by the programmer. True objects are, therefore, part of the server module. The rest are surrogate objects with methods that are produced as language-specific stubs when ILU parses the interface specifications. These stubs invoke the true object's methods. A surrogate object is used by clients when the server module is contained within a different program instance or uses a different data representation.

Inheritance and Object Subtypes

The ILU object model provides for multiple inheritance. ILU is designed so that any given subtype provides all necessary methods described by a supertype. For languages that support multiple inheritance, the ILU subtype tree should be a mirror of the language's subtype tree. In languages that only support single inheritance, ILU requires that an ILU-specific multiple-inheritance object system be embedded -- this is supplied as part of the ILU environment.

The subtype system in ILU supports level branding, which helps to distinguish subtypes (since each is created with a distinct interface name or with a distinct type name). This system helps the programmer indicate where a semantic difference would occur.

Object Instantiation

To use an ILU object, a client must obtain the language-specific object for the ILU object being called. This can be done in a couple of different ways. The client can call or receive an object from a separate ILU object, or the client can invoke a call-by-address service, which returns a "string-binding" handle. The ILU run-time library provides services to acquire the handle and return the named object to the caller. All of this implies that the client is communicating with a server module.

In addition, the client can request an object purely by name; the entire process can be bootstrapped to a name-server facility provided by a service such as PARC's Name and Maintenance Server. This facility allows servers to register object names on a network-wide basis.

The string-binding handle provides the basis for ILU's string-based reference to an object. This facility is required for dealing with name services. The handle contains:

  • Server ID. This is a string that identifies the kernel server to which the object belongs. Any program can separate its objects into one or more groups, and associate its groups with one or more kernel servers. This allows a high degree of control and flexibility, although it comes at the expense of some initial confusion.
  • The Instance handle. This identifies a single instantiation of any given object.
  • The Most-Specific Type ID (MSTID). This provides a type ID for the object.
  • Contact information. These details explain how a client of the object may send messages to the instantiated object.

The server ID, Instance handle, and MSTID can contain any legal ASCII character except NUL. ILU borrows the URL naming convention for specifying handles.

The combination of Server ID and MSTID form the complete Object ID -- this is what ILU uses to access any specific instantiated object within the ILU system.

The contact information section within the handle provides information about the object's protocol, transport information, and any parameters that might influence the transport. ILU currently ignores all but the protocol field within the contact information section -- the balance of the fields are for future expansion.

Garbage Collection

ILU supports a simple garbage-collection algorithm. The collection algorithm requires that clients holding surrogate instances of the collectable object register those instances with the server. This way, the server has a list of clients that are using (or holding, to use the ILU terminology) copies of the object that is marked as being collectable. As each client finishes using (holding) its copy, it unregisters itself from the server. As soon as all listed clients unregister (and after a pair of programmer-set timers have expired), the server invokes the collection algorithm.

The first timer is a dormancy timer that is set long enough to allow debugging, and the second is a fail-safe timer to deal with client failure.

Connections, Bindings, and CORBA

ILU does not maintain an independent set of connections. There is no pointer back to a server module -- ILU requires that such information be passed as a parameter to the client class.

To help with this, ILU implements a binding and naming facility. This allows a server module to publish an object, so that a client module can import the object with no knowledge other than the object's name. The methods provided for the bindery are simple, consisting only of the methods Publish, Withdraw, and Lookup.

ILU follows the type and exception model of CORBA and supports CORBA's IDL as an alternate to the ISL interface-description language. However, ILU is not yet a full implementation of the CORBA specification. It does not provide several features of the CORBA 2.0 specification -- most notably, the Repository concepts and the Dynamic Invocation Interface. It also does not supply the Basic Object Adapter Interface. Instead, ILU supplies an adapter interface of its own design.

In all, ILU is a nice extension to several threads of thought that started with Arjuna and Isis, from the University of Newcastle and Cornell University, respectively.

Putting It All Together

Recall that, as described, ILU is basically about interfaces. Example 1 (recycled from the C Language Tutorial that comes from ILU, which itself recycles the classic Calc interface from Kernighan and Ritchie) describes a typical interface specification.

Example 1 defines an interface with the name of MyInterface, and an object, Calculator, with the methods Add, Subtract, GetValue, SetValue, Multiply, and Divide. Divide raises the exception DivideByZero, which we define right after the interface name. An interface is the mechanism that ILU provides to avoid confusion when two programmers call objects by the same name.

The object itself is defined as a list of methods, bounded by the keywords METHODS and END, with the elements of the list separated by commas. The language owes a fair bit of its syntax to the Modula family. Comments in ISL are defined by quote marks at the beginning and end of the comment. In addition, the DOCUMENTATION keyword provides a one-line comment field for the object that is preserved when parsed by ISL.

ILU provides tools to check the syntax of an ISL specification without attempting to compile the specification. The tool returns errors and supplies the implementor with information useful in later debugging.

The final output of the interface generator is a language-specific mapping of the interface to the application language in which the programmer has actually chosen to implement the module. This mapping is generated by the family of programs known as the stubbers -- as the name implies, the stubbers generate the language-specific stubs that ILU requires to map the ILU syntax into the actual implementation syntax.

The True Object

Once the interface is designed, the next thing the implementor needs to do is provide, naturally enough, an implementation of the module. This can be done in any of the languages for which there is an ILU binding. You need not be constrained to C or C++. Lisp and Python are currently supported as alternate programming languages, and other bindings could be developed.

Once the methods of the true object are implemented, you generate a library that combines the code for the methods and the stubs generated by the stubber.

Putting It All Together: Part II

To provide the example calculator as a network service, a few more steps need to be taken. The first step is to provide a "factory" (to build calculator objects) by creating a factory type. The interface is defined in ISL, just as for the calculator type. It might look something like Example 2 and, of course, needs to be implemented.

The next step is to publish the name of the program acting as a server for Calculators. This allows programs that wish to use Calculators to request an instance of a Calculator knowing only the name of the server.

The server program provides some relatively simple services. It creates a single instance of the Factory object, publishes the name of the factory object so that other modules know where to obtain calculators (to continue with our example), then loops, looking for requests to furnish calculators to other modules.

In ILU, the name of an object has two parts, the instance handle and the name of its kernel server (Server ID). For example, you could call the server CalculatorFactory.good_karma.org. At this point, we could use a simple instance handle, such as Factory. If you are expecting more than one instance of an object to be used, you should use more qualifiers correspondingly. All that remains is for the server to call the appropriate language-specific PublishObject procedure. An example (for C) is ILU_ C_PublishObject.

The final step in all of this, of course, is to actually use the Calculator object. The client program makes a call to the language-specific lookup routine, for example, ILU_ C_LookUpObject, passing the name of the factory as a parameter. The lookup routine invokes an ILU kernel call that queries the name service and returns an instance pointer to the client. This allows the client to call the single method provided by our example factory -- CreateNewCalculator, which will return a Calculator object.

A Real World Language-Binding Example: Python

To illustrate ILU language binding, I'll use Python as an example. (For more information on Python, see "Hector: Distributed Objects in Python," by David Arnold, Andy Bond, and Martin Chilvers on page 13 of this issue.)

ILU maps the language-specific class types into an ILU specification. Python names are constructed from interface-definition names by replacing any hyphens with underscores to achieve compliance with the Python syntax; for example, FOO-ILU-Name becomes FOO_ILU_Name.

For each interface specified, ILU needs to designate two Python modules -- a skeleton module containing the ILU server stubs, and a module containing common definitions.

ILU constants and exceptions are translated to Python variables. Constants are initialized with the value of the constant, exceptions are initialized with a string containing the name of the exception.

Types from ILU are mapped to the appropriate Python type. For example, the ILU types BYTE, INTEGER, SHORT INTEGER, and SHORT CARDINAL are all mapped into the Python type int. LONG INTEGER, CARDINAL, and LONG CARDINAL are mapped to the Python type long int.

To actually create an ILU module from Python, the ILU run-time interface ilu() is called using the Python import function. Python objects must import and inherit the skeleton class containing the names of the interface and object they wish to implement. This skeleton is generated from the ILU stubber for the Python language.

All ILU objects have built-in methods that provide name and addressing information for the server object, see Table 2.

Clients written in Python create objects using one of three methods:

  • If the string binding handle and class are known, call the ILU kernel module ilu.ObjectofSBH(<class>, <string binding handle>).
  • If the Object ID is known and the class has been published, simply call ilu.Lookup(<String ID>, <Instance Handle>, <Class>).
  • Obtain an instance of the object via a parameter return.

And there you have it -- an elegant and simple method of distributing applications around the network. ILU provides many more services than I've been able to cover here -- a full manual and several tutorials are available along with the ILU package.

DDJ


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.