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
.1
Two 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.