Part II: Core CORBA
Chapter 4. The OMG Interface Definition Language
4.7 User-Defined Types
4.7.10 Constant Expressions
IDL offers arithmetic and bitwise operators, as shown in Table 4. 2. These operators are familiar from C++, but not all of them behave like their C++ counterparts.
Table 4.2. IDL operators.
Operator Type IDL Operators
Arithmetic + - * / %
Bitwise | & ^ < >> ~
Semantics for Arithmetic Operators
The arithmetic operators apply to both floating-point and integer expressions with the exception of %, which must have integer operands.
The arithmetic operators do not support mixed-mode arithmetic. You cannot mix integer and floating-point constants in the same expression, and there is no form of explicit type casting. The restriction exists to keep IDL compiler implementations simple.
Integer expressions are evaluated as unsigned long unless a negative integer is contained in the expression, which causes evaluation as long. The result is coerced back into the target type. If intermediate values in the expression exceed the range of long or
unsigned long or if the resulting value does not fit into the target type, the behavior is undefined.
Here are some examples of arithmetic constant expressions:
const short MIN_TEMP = -10; const short MAX_TEMP = 35;
const short AVG_TEMP = (MAX_TEMP + MIN_TEMP) / 2;
const float TWICE_PI = 3.14 * 2.0; // Can't use 3.14 * 2 here
Bitwise operators apply only to integer expressions. Shifting a short or unsigned short value by more than 16 bits or shifting a long or unsigned long by more than 32 bits has undefined behavior.
In C++, right-shifting a negative number has implementation-defined behavior (most implementations sign-extend). In IDL, in contrast, the right-shift operator >> always performs a logical shift. This means that the value of RHW_MASK in this example is guaranteed to be 0xffff even though it is obtained by right-shifting a signed value:
const long ALL_ONES = -1; // 0xffffffff const long LHW_MASK = ALL_ONES < 16; // 0xffff0000
const long RHW_MASK = ALL_ONES >> 16; // 0x0000ffff, guaranteed
4.8 Interfaces and Operations
As we state in the introduction to this chapter, the focus of IDL is on interfaces and operations. Here is a simple interface for a thermostat device:
interface Thermostat { // Read temperature short get_temp();
// Update temperature, return previous value short set_nominal_temp(in short new_temp); };
This definition defines a new CORBA interface type called Thermostat. The interface offers two operations: get_temp and set_nominal_temp. If a client accesses an object via its interface (or, more correctly, via an object reference to that interface), it does so by invoking operations on the interface. For example, to read the current room temperature, a client invokes the get_temp operation, and to change the setting of a thermostat, the client invokes the set_nominal_temp operation.
The act of invoking an operation on an interface causes the ORB to send a message to the corresponding object implementation. If the target object is in another address space, the ORB run time sends a remote procedure call to the implementation. If the target object is in the same address space as the caller, the invocation is usually accomplished as an ordinary function call to avoid the overhead of marshaling and using a networking protocol. Some ORBs also offer a shared memory transport to optimize calls to implementations that are in a different address space but on the same machine.
Intuitively, IDL interfaces correspond to C++ classes, and IDL operations correspond to C++ member functions. However, there are differences between C++ class definitions and IDL interface definitions. IDL interfaces define only the interface to an object and say nothing about the object's implementation. This has a number of consequences.
IDL interfaces do not have a public, private, or protected part. By definition, everything in an interface is public. Things are made private by simply not saying anything about them.
IDL interfaces do not have member variables. IDL has no concept of member variables, not even public ones. Member variables store state, and the state of an object is an implementation concern.[2] Of course, you can create objects that store state, and you can allow clients to manipulate that state. However, clients must do this by invoking operations on the interface, and the details of how the state of an object is changed are hidden behind its interface.
[2] IDL attributes are not public member variables even though they look as if they
were. We discuss IDL attributes in Section 4.14.
As you can see, CORBA carefully separates the interface of an object from its implementation. There is no way for a client to interact with an object except to invoke an operation (or to set or get an attribute). This is what makes possible the contract between client and server and permits clients and servers to be implemented on different platforms or in different languages and still communicate transparently.
Every CORBA object has exactly one interface, but there can be thousands of objects of the same interface type in a distributed system. In that respect, IDL interfaces correspond to C++ class definitions and CORBA objects correspond to C++ class instances. The difference is that CORBA objects can be implemented in many different address spaces. You can implement interface instances in a single address space, spread them over a number of processes on the same machine, or spread them over a number of processes on different machines. However, an interface instance denoted by an object reference is CORBA's only notion of a remotely addressable entity. IDL interfaces therefore define the smallest granularity of distribution in a CORBA system. The way an application is broken into interfaces determines how it can be distributed over physical address spaces; application functionality can be distributed only if there is an interface to access that functionality.