Tuesday, April 18, 2006

Interfaces, Local Interfaces, ValueTypes and Abstract Interfaces

CORBA IDL Series Continued (Part 2)

OMG IDL Interface:

Interfaces form the heart of the client-server contract. In IDL it is represented using the following EBNF -

<interface> ::= <interface_dcl> <forward_dcl>

<interface_dcl> ::= <interface_header> “{” <interface_body> “}”

<forward_dcl> ::= [ “abstract” “local” ] “interface” <identifier>

<interface_header> ::= [ “abstract” “local” ] “interface”
<identifier> [ <interface_inheritance_spec> ]

<interface_body> ::= <export>*

<export> ::= <type_dcl> “;” <const_dcl> “;” <except_dcl> “;” <attr_dcl> “;” <op_dcl> “;”

Interfaces also forms a namespace for identifiers scoped inside it. Apart from the attribute and operation declarations, types, exceptions and constants can also be defined inside an interface namespace.

Interfaces support multiple inheritance.

Salient notes about Interfaces

Derived interfaces can redefine any identifier previously defined in the base interfaces, but for attributes and operations.

An interface cannot be direct base of another more than once; however it can be indirect base multiple times. For example

interface A {...}
interface B : A {...}
interface C : A, B {...} // okay
interface D : A, B, A {...} // error

Derived interfaces can refer identifiers defined in base interfaces by using complete scope. The references need to obviously unambiguous. Also references to identifiers get bound to interface when they are defined. Their binding does not change if it is redefined. For example

const long L = 3;
interface A {
typedef float coord[L]:
void f (in coord s); // s has three floats
};
interface B {
const long L = 4;
};
interface C: B, A { }; // f is still taking fload coord[3]

Local Interfaces:

These interfaces cannot be marshalled out - sent in a remote operation; hence are local. Any type containing these themselves become local. They can however be used in valuetype operations. Also valuetypes can support a single local interface as supporting an interface does not make the valuetype syb types of the inetrface. Such valuetypes can then be marshalled.

The table below shows inheritance structures


-----------------------------
I LI AI VT BVT AVT
-----------------------------
I M - M - - -
-----------------------------
LI M M M - - -
-----------------------------
AI - - M - - -
-----------------------------
VT SS SS SM S - M
-----------------------------
AVT SS SS SM - - M
-----------------------------
BVT - - - - - -
-----------------------------
I - Remote Interface
LI - Local Interface
AI - Abstract Interface
VT - Value Type
BVT - Boxed Value Type
AVT - Abstract Value Type
M - Can inherit multiple
- - Cannot inherit or support
SS - Can support single
SM - Can support multiple
ValueTypes

In CORBA, objects passing is by reference. When an IDL interface parameter is passed, it is converted to a reference and is passed to the peer. Any method call on the reference effects the original object. Sometimes, it is useful to encapsulate data only and the methods just manipulate the data. When such objects are passed, it needs to be copied so that peers can independently work on the encapsulated data. Such a requirement is not catered for by IDL interfaces. IDL structs do allow the data to be copied across between peers, but does not allow encapsulating data.

To answer the above need, ValueTypes were introduced. ValueTypes are in a way cross between interfaces and structs. While it allows method calling and inheritance, its value is copied over instead of reference being passed. The peer end constructs the Valuetype instances with the data that has come over the wire.

Types of ValueTypes

ValueTypes could be either
  • concrete value types
  • abstract value types.
Concrete valuetypes are those that have data encapsulation. Such valuetypes, obviously can be instantiated. On the other hand, when a valuetype is a pure bundle of operation and contains no state, it is said to be abstract and cannot be instantiated.

Boxed valuetypes is a special type of concrete valuetypes which does not have any operations and has only a single datamember. Typically this is used if data structures such as string or sequences need null parameter passing.

EBNF of ValueType

<value> ::= ( <value_dcl> <value_abs_dcl> <value_box_dcl> <value_forward_dcl>)

Regular Value Type

<value_dcl> ::= <value_header> “{“ < value_element>* “}”

<value_header> ::= [“custom” ] “valuetype” <identifier> [<value_inheritance_spec> ]

<value_element> ::= <export> < state_member> <init_dcl>

<value_inheritance_spec> ::= [ “:” [ “truncatable” ] <value_name> { “,” <value_name> }* ][ “supports” <interface_name> { “,” <interface_name> }* ]

<value_name> ::= <scoped_name>

State declaration

<state_member> ::= ( “public” “private” ) <type_spec> <declarators> “;”

Important charecteristics of ValueTypes
  • ValueTypes are local. They are implemented and reside locally. When a valuetype is sent across the wire, only its state is really sent and the object is recreated at the peer end using the state marshalled across.
  • Valuetypes can singly inherit from concrete valuetype and multiply inherit from abstract valuetype. I presume the restriction of single inheritance from concrete valuetype is to avoid the issues because of multiple implementation inheritance. Valuetypes can also support a single IDL interface or a local interface. Further more, it can support multiple abstract interfaces.
  • Sharing semantics - Valuetype instances can be shared between other valuetype instances. This allows the preservation of relationship between instances when these objects are marshalled over.
  • Null semantics - strings, structs, sequences and other data types in IDL do not support passing of null value. However, this can be done for a ValueType object.
  • Copy semantics of the valuetype are only guarenteed when the valuetype instances are part of an IDL interface method signature. If a valuetype instance is used in a language specific function call or as part of a valuetype operation, then these instances are passed using the programming language specific reference semantics.
Inheritance in ValueTypes

  • Abstract valuetypes can inherit from any number of abstract valuetypes and support any number of abstract interfaces. It can also additionally support a single interface. Abstract valuetypes obviously cannot inherit from concrete valuetypes.
  • Concrete valuetypes can only inherit from a single concrete valuetype. It however can inherit from multiple abstract valuetypes and support multiple abstract interfaces. It can also additionally support a single interface. An interesting problem arises when concrete valuetypes inherit from other concrete valuetypes. When they are marshalled over, it could so happen that the recieving peer only has information till some of the parent valuetypes. Specifying this valuetype, then to be truncatable allows the receiving side to truncate the value to the parent valuetype.
Substitutability

When a valuetype instance is to be passed into an CORBA operation that takes -

1) Interface reference - When a valuetype supports an interface, it is not naturally the subtype of the interface. It cannot be passed in situation where a paremeter type is the base interface. In this case, through special language mapping mechanisms, the valuetype needs to be converted to the interface reference type to be passed.

2) Abstract Interface - Derived valuetype instance is a subtype of the abstract interface and hence can be passed.

3) ValueType - Yes. If the receiving peer has the same version of the implementation of valuetype, then it is no problem. If not, then it tries to (1) load the implementation if possible (2) truncate to a base class if truncatable (3) throw NO_IMPLEMENT.