This chapter describes the features of the IDL language. Appendix A, "IDL Reference" of the OrbixWeb Reference Guide provides some additional reference material on IDL. This includes the full syntax of the language and a list of IDL keywords.
4.1 IDL Interfaces
An IDL interface provides a description of the functionality that will be provided by an object. An interface definition provides all of the information needed to develop clients that use the interface. An interface definition typically specifies the attributes and operations belonging to that interface, as well as the parameters of each operation. Defining the interfaces between components is the most important aspect of distributed system design; therefore interfaces are the single most important feature of IDL.
// IDL
interface Account {
// Attributes to hold the balance and the name
// of the account's owner.
attribute float balance;
readonly attribute string owner;
// The operations defined on the interface.
void makeDeposit(in float amount,
out float newBalance);
void makeWithdrawal(in float amount,
out float newBalance);
};
The Account interface defines attributes balance and owner; these are properties of an Account object. The attribute balance may take values of type float which is one of the basic types of IDL and represents a floating point type (such as 102.31). The attribute owner is of type string and is defined to be readonly.1Two operations,
makeDeposit() and makeWithdrawal(), are provided. Each has two parameters of type float. Each parameter must specify the direction in which the parameter is passed. The possible parameter passing modes are:in |
the parameter is passed from the caller (client) to the called object.
|
out |
the parameter is passed from the called object to the caller.
|
inout |
the parameter is passed in both directions.
|
In our example,
amount is passed as an in parameter to both functions and the new balance is returned as an out parameter. The parameter passing mode must be specified for each parameter, and it is used both to improve the "self-documentation" of an interface and to help guide the code that IDL is subsequently translated to.Line comments are introduced with the characters
// as shown in the example. Comments spanning more than one line are delimited by /* and */. For example:
// IDL /* This commment spans more than one line. */Multiple IDL interfaces may be defined in a single source file, but it is common to define each interface in its own file.
oneway so that the caller is not blocked and can continue in parallel to the server. For example, we could provide a oneway operation on our Account interface to send a notice to the account:
// IDL
interface Account {
// Details as before.
// Send notice to account.
oneway void notice(in string notice);
};
A oneway operation must specify a void return type and cannot have out or inout parameters and it also cannot have a raises clause (see section 4.5).
Oneway operations are supported because it is sometimes important to be able to communicate with a remote object without waiting for a reply. A oneway operation differs from a normal operation (an operation not designated as
oneway) that happens to have no out or inout parameters and a void return type: calls to the normal operation will block until the operation request has been carried out. 4.3 Context Clause
An IDL operation may also have a context clause associated with it. A client can maintain one or more CORBA context objects, which provide a mapping from identifiers (string names) to string values. An IDL operation can specify that it is to be provided with the client's mapping for particular identifiersit does this by listing these identifiers following the operation declaration. For example, in the following interface definition, the operation op() specifies that it is to receive a context with two mappings: one for identifier accuracy, and one for base:
// IDL
interface I {
void op(in unsigned long s)
context("accuracy", "base");
};
Only the identifiers (string names) are specified in the context expression. Each identifier name must begin with an alphanumeric character and can only contain alphanumerics, digits, `_' and `.'. An identifier specified in a context clause can also contain the character `*', but this character must appear at the end; it indicates that the operation is to receive the mapping for all identifiers in the client context with matching leading names. For example, an identifier "sys_*" in a context clause would match entries such as "sys_printer" and "sys_quality" in the client's context.The advantage of a context is that a set of identifier:string mappings can be specified in one location of a large program, and a subset of these mappings can be passed to IDL operation calls spread throughout the program. The mappings can then be maintained easily in one location.
Nevertheless, contexts are one of the least important features of IDL, and extensive use should be avoided.
The following example illustrates the use of a module: the interfaces related to banks are defined within a module,
Finance:
// IDL
module Finance {
interface Bank {
. . .
};
interface Account {
. . .
};
};
The full (or scoped) name of Account is then Finance::Account.
Bank interface:
// IDL
interface Bank {
exception Reject {
string reason;
};
exception TooMany {}; // Too many accounts.
Account newAccount(in string name)
raises (Reject, TooMany);
void deleteAccount(in Account a);
};
The Bank interface defines two operations:newAccount() |
creates an account whose owner is the person or company whose name is passed as the parameter; the operation returns a reference to an Account object.
|
deleteAccount() |
deletes an account.
|
The
newAccount() operation specifies, using the raises expression, that it may raise two exceptions called Reject and TooMany. The exceptions Reject and TooMany are defined within the Bank interface. The Reject exception defines a member of type string, which will be used to specify the reason that the bank rejected the request to create a new account. The TooMany exception does not define any members.As well as user-defined exceptions, a set of standard exceptions is defined by CORBA. These correspond to standard runtime errors which may occur during the execution of a request and are listed in Appendix A, "IDL Reference" of the OrbixWeb Reference Guide.
Exceptions provide a clean way to allow an operation to raise an error to a caller. It allows an operation to specify that it may raise a set of possible error conditions. Because IDL provides a separate syntax for exceptions, this can be translated into exception handling code in programming languages that support them (including Java).
4.6 Inheritance
Our banking application also needs to consider that there are many types of bank account: checking (or current) accounts and savings accounts, for example. Both checking accounts and savings accounts share the properties of an account and respond to the same operations but these operations have different behaviour. They may also have additional properties and operations.Account interface is called a base interface of CheckingAccount and SavingsAccount. Interfaces CheckingAccount and SavingsAccount are called derived interfaces of Account.
|
We can define interface
CheckingAccount as:
// IDL
interface CheckingAccount : Account {
readonly attribute overdraftLimit;
boolean orderChequeBook();
};
It defines one attribute overdraftLimit, but inherits the attributes balance and owner defined in its base interface Account. Similarly, it inherits the operations makeDeposit() and makeWithdrawal() from Account, and defines a new operation orderChequebook(). An implementation of interface CheckingAccount may provide code different to an implementation of interface Account.We can define interface
SavingsAccount as:
// IDL
interface SavingsAccount : Account {
float calculateInterest();
};
An interface may be derived from any number of base interfaces; this is known as multiple inheritance. For example, a premium account might have the properties of both a checking account and a savings account; that is, it is an interest earning account which may also have a cheque book. Thus the inheritance hierarchy is as shown in Figure 4.2.

The
SavingsAccount interface is defined as:
// IDL
interface SavingsAccount : Account {
float calculateInterest();
};
Then PremiumAccount interface may then be specified in IDL as follows:
// IDL
interface PremiumAccount :
CheckingAccount, SavingsAccount {
// New attributes and operations defined here.
};
If an interface inherits from two interfaces which contain a definition (constant, type, or exception) of the same name, then references to this interface in the derived interface will be ambiguous unless the name of the definition is qualified by its interface name, that is, unless a scoped name is given (see section 4.13). Note that it is illegal to inherit from two interfaces with the same operation or attribute name.
4.7 The Basic Types of IDL
Table 4.1 lists the basic types supported in IDL.
// IDL
interface I {
void op(in any a);
};
A process that receives an any must determine what type of value it contains and then extract the value. The any type is described in Chapter 18, "Type any".
4.8 Constructed Types
As well as the basic types listed above, IDL provides three constructed types: struct, union and enum.4.8.1 Structures
A struct data type allows related items to be packaged together. For example,
// IDL
struct PersonalDetails {
string name;
short age;
};
interface Bank {
exception Reject {
string reason;
};
Account newAccount(in string name,
in short age) raises (Reject);
PersonalDetails getPersonalDetails(
in string name);
void deleteAccount(in account a);
};
The struct PersonalDetails has two members: name of type string and age of type short. The operation getPersonalDetails() returns one of these structs.
// IDL
enum colour { red, green, blue, yellow, white };
This is more readable than defining colour as a short. The order in which the identifiers are named in the specification of an enumerated type defines the relative order of the identifiers. This order may be used by a specific programming language mapping which allows two enumerators to be compared.
union type provides a space saving type whereby the amount of storage required for a union is the amount necessary to store its largest element. A tag field is used to specify which member of a union instance is currently assigned a value.
// IDL
union token switch (long) {
case 1 : long l;
case 2 : float f;
default: string str;
};
The identifier following the union keyword defines a new legal type. A union type may also be named using a typedef declaration (see section 4.12).
IDL unions must be discriminated: that is, the
union header must specify a tag field that determines which union member is assigned a value. In the example, the tag is called token and is of type long. Each expression that follows the case keyword must be compatible with the tag type. The type specified in parentheses after the switch keyword must be an integer, char, boolean or enum type. A default case can appear at most once in a union declaration. 4.9 Arrays
IDL provides multi-dimensional fixed-size arrays to hold lists of elements of the same type. The size of each dimension should be specified in the definition. Some example array types are:
// IDL // A 1-dimensional array. Account bankAccounts[100]; // A 2-dimensional array. short gridArr[10][20];Types
bankAccounts and gridArr can be used, for example, to define parameters to an operation.
sequence and string, which are described in the following subsections.
sequence data type allows lists of items to be passed between objects. A sequence is similar to a one-dimensional array; it has two characteristics: a maximum size, which is fixed at compile time, and a length, which is determined at runtime. A sequence differs from an array in that a sequence is not of fixed size (although a bounded sequence has a fixed maximum size). Hence, a sequence is a more flexible data type, and should be used in preference to an array except when the list of elements to be passed is always of the same size.A sequence may be bounded or unbounded, depending on whether the maximum size is specified. For example, the type declaration:
// IDL sequence<long, 10> vectorTen;defines a bounded sequence of size
10. The sequence vectorTen may be of any length up to the bound, 10. The type declaration:
// IDL sequence<long> vector;defines an unbounded sequence.
A sequence that is used within an interface definition must be named by a typedef declaration (see section 4.12) before it can be used as the type of an attribute definition or as a parameter to an operation. For example:
// IDL typedef sequence<long, 10> vectorTen; attribute vectorTen vector; // The following definition is not allowed: attribute sequence<long, 10> illegalVector;A sequence that appears within a struct or union definition does not have to be named.
string, which is similar to a sequence of char. A string may be bounded or unbounded depending on whether its length is specified in the declaration. A length may be specified for a string as shown in the example below:
// IDL
interface Bank {
// Other details as before.
// A bounded string.
attribute string sortCode<10>;
// An unbounded string.
attribute string address;
};
// IDL
interface Bank {
const long MaxAccounts = 100000;
// Rest of definition here.
};
The value of an IDL constant cannot change. Constants may be defined in an interface or module, or at global, or file level, scope (outside of any interface or module).Constants of type
long, unsigned long, short, unsigned short, char, boolean, float, double and string can be declared. Note that constants of type octet cannot be declared.
typedef declaration can be used to define a meaningful or a more simple name for a basic or a user-defined type. For example:
// IDL typedef short size;defines
size as a synonym for short. Consequently the parameter declaration:
// IDL in size iis equivalent to:
// IDL in short iThe definition:
// IDL typedef Account Accounts[100];allows a subsequent definition (for example, as a member of a structure):
// IDL Accounts bankAccounts;
interface followed by the identifier that names the interface, for example:
// IDL interface Bank;The interface definition must appear later in the specification.
A qualified or scoped name has the form
<scoped_name>::<identifier>. Within a scope, a name may be used in its unqualified form.
#include directive allows an IDL file to be included in other files.As for a C++ include file, the following directives should be used in an IDL file that is potentially included in many other IDL files:
#ifndef <some_unique_name> #define <some_unique_name> Body of the idl file. #endifOther preprocessing directives available in IDL are:
#define, #undef, #include, #if, #ifdef, #ifndef, #elif, #else, #endif, #defined, #error, #pragma.
NamedValue,
NVList,
Request,
Context,
Principal,
TypeCode,
ORB,
BOA,
Environment.
Environment is not implemented in the OrbixWeb IDL to Java mapping.
NamedValue, Principal and TypeCode are available in an IDL file only if it includes the directive:
#include <orb.idl>Interface name
Object (the implicit base interface of all interfaces) is available in all files.
readonly attribute need not be a constant: two reads of an attribute where there is an interleaving operation call can return different values.