As huge numbers of CORBA objects can be present in any project (in some name-space), there would certainly be name-space-clashes if all these objects needed to have unique names. Therefore, IDL allows the definition of so-called modules, which specify a separate name-space, similar to the name-space-functionality of C++. Now, for any interface, a module can be specified, as shown in the following example.
module FruitsBasket { interface Apple {}; interface Orange {}; }; |
Here, we define two objects: Apple and Orange, within the FruitsBasket module. If we wish to reference an object from another module, we have to give the full object's reference.For example, from the VegetablesBasket module, references to Apple are made as follows: FruitsBasket::Apple.
It is also possible to 'reopen' the same module to add interface definitions: the following example is strictly equivalent to the precedent one.
module FruitsBasket { interface Apple {}; }; module FruitsBasket { interface Orange {}; }; |
IDL, like C++ has also pre-compiler directives: #include and #pragma are supported (these directives are expanded by the idl-compiler). #include has semantics similar to those in C/C++. It allows you to split different interfaces from the same module in different files for clarity.
/* this is a comment like in C */ // this is a comment like in C++ : both are valid // this code is the file apple.idl #include "orange.idl" module FruitsBasket interface Apple {}; }; |
// this code is the file orange.idl module FruitsBasket interface Orange {}; }; |
Because IDL's main-purpose is to achieve portability between different languages, on different machines and operating systems, it is very strongly typed. Here are the most basic (standard) CORBA types:
Table 1-1. Basic CORBA types
Type | Signification |
---|---|
short | 16 bit signed integer |
unsigned short | 16 bit unsigned integer |
long | 32 bit signed integer |
unsigned long | 32 bit unsigned integer |
long long | 64 bit signed integer |
unsigned long long | 64 bit unsigned integer |
float | 32 bit IEEE float |
double | 64 bit IEEE float |
long double | 128 bit float |
boolean | boolean value: TRUE or FALSE |
octet | 8 bit byte |
char | 8 bit character (ISO latin-1) |
wchar | international character format. FixMe: who knows what format? |
string | character string based on char |
wstring | character string based on wchar |
Their use is fairly straightforward: here is some IDL interface declaration using the string type and the float type:
module FruitsBasket { interface Apple { attribute string color; }; interface Orange { attribute float size; }; }; |
Each object gets an attribute of type float and type string.
IDL allows you to define constants thanks to the const modifier (like in C++). Here is some sample IDL code:
module FruitsBasket { interface Apple { attribute string color; const float weight = 2.3; const string type = "sample type"; }; interface Orange { attribute float size; }; }; |
It is also possible to define your own types using the typedef keyword (again, like in C and C++). Again, sample code which will define an Apple-object with the type attribute which is a string.
module FruitsBasket { typedef string fruit_type; interface Apple { attribute fruit_type type; }; interface Orange { }; }; |
We have also standard C/C++ structures, enumerations and arrays. Structures, enumerations and fixed size arrays are straight C code like typedef:
module calendar { enum a_month { january, february, march, april, may, june, july, august, september, october, december }; enum a_day { monday, tuesday, wednesday, thursday, friday, saturday, sunday }; typedef long a_year; struct a_date { a_day the_day; a_month the_month; a_year the_year; }; interface calendar { attribute a_date the_date; // 1 dimensional array typedef a_date a_date_array[20]; attribute a_date_array the_date_array; // 2 dimensional array typedef a_date_array a_date_array_multi[20]; attribute a_date_array_multi the_date_array_multi; }; }; |
Variable-size arrays are called sequences in CORBA:
module calendar { interface calendar { /* This defines a one dimensional array * of longs with a maximum size of 20. */ typedef sequence <long,20> array_1; // an unbounded one dimensional array of strings typedef sequence <string> array_2; // more tricky: a sequence of sequences: used // to simulate multi dimensional variable size arrays typedef sequence <sequence <long,20> > array_3; }; }; |
All these standardized types allow programmers to define object attributes and methods. Objects methods (functions) are declared with:
module FruitsBasket { interface Apple { // this is the declaration of the eat_me method // which takes as parameters a boolean variable. void eat_me (in boolean eat_yes_or_not ); // returns whether the Apple was eaten or not. boolean eaten (); // returns whether the apple was eaten or not and the surname // and name of the man who ate the Apple. boolean who_ate ( out string who_surname, out string who_name ); }; }; |
These declarations are quite like C++ code, except for the in decoration: parameters are decorated by any one of three 3 types: in, out, inout. Their semantics are as follows: in-parameters are data send from the client to the object, out-parameters are data send from the object to the client, and inout parameters are first send from the client to the object, and then returned to the client.
All these method declarations are synchronous operations, ie. using one of these methods means that your program will wait for the object to answer to continue its execution. It is possible to define asynchronous methods so that the method caller continues to execute and does not block until the object returns, by declaring a method with the oneway-keyword.
module FruitsBasket { interface Apple { // this is the declaration of the eat_me method // which takes as parameters a boolean variable. void eat_me (in boolean eat_yes_or_not ); // returns whether the Apple was eaten or not. // asynchronous method. oneway boolean eaten (); // returns whether the apple was eaten or not and the surname // and name of the man who ate the Apple. boolean who_ate ( out string who_surname, out string who_name ); }; }; |
It's also possible to define exceptions (similar to C++ exception classes).
module FruitBasket { exception no_more_fruits { string reason; }; interface Apple { // whatever methods we wish }; }; |
Finally, a method capable of throwing exceptions can declare this as follows:
module FruitsBasket { exception no_more_fruits { string reason; }; interface Apple { void eat_me (in boolean eat_yes_or_not ) raises ( no_more_fruits ); // whatever methods we wish }; }; |
Like C++-classes (or Java interfaces), interfaces may inherit from other interfaces, and multiple inheritance is supported. The syntax is similar to C++'s syntax. An important difference is that IDL does not support overloading or having different methods with the same name but different signatures.
module FruitsBasket { exception no_more_fruits { string reason; }; interface generic_fruit { void eat_me (in boolean eat_yes_or_not ) raises (no_more_fruits); oneway boolean eaten (); }; interface generic_fruit_one { boolean who_ate ( out string who_surname, out string who_name ); }; interface Apple : generic_fruit, generic_fruit_one { // Apple specific methods go there. }; }; |
We have shown the various IDL types, some ways to create new ones and the declaration of attributes, methods and exceptions. However, the interested reader may read the authorative IDL-definition from the CORBA standard and see a few additional types such as any, TypeCode and union. However, these types are not so important for this tutorial.