6 OMG IDL to Erlang Mapping
6.1 OMG IDL to Erlang Mapping - Overview
The purpose of OMG IDL, Interface Definition Language, mapping is to act as translator between platforms and languages. An IDL specification is supposed to describe data types, object types etc.
CORBA is independent of the programming language used to construct clients or implementations. In order to use the ORB, it is necessary for programmers to know how to access ORB functionality from their programming languages. It translates different IDL constructs to a specific programming language. This chapter describes the mapping of OMG IDL constructs to the Erlang programming language.
6.2 OMG IDL Mapping Elements
A complete language mapping will allow the programmer to have access to all ORB functionality in a way that is convenient for a specified programming language.
All mapping must define the following elements:
- All OMG IDL basic and constructed types
- References to constants defined in OMG IDL
- References to objects defined in OMG IDL
- Invocations of operations, including passing of parameters and receiving of results
- Exceptions, including what happens when an operation raises an exception and how the exception parameters are accessed
- Access to attributes
- Signatures for operations defined by the ORB, such as dynamic invocation interface, the object adapters etc.
- Scopes; OMG IDL has several levels of scopes, which are mapped to Erlang's two scopes.
6.3 Getting Started
To begin with, we should decide which type of objects (i.e. servers) we need and if two, or more, should export the same functionality. Let us assume that we want to create a system for DB (database) access for different kind of users. For example, anyone with a valid password may extract data, but only a few may update the DB. Usually, an application is defined within a
module
, and all global datatypes are defined on the top-level. To begin with we create a module and the interfaces we need:// DB IDL #ifndef _DB_IDL_ #define _DB_IDL_ // A module is simply a container module DB { // An interface maps to a CORBA::Object. interface CommonUser { }; // Inherit the Consumer interface interface Administrator : CommonUser { }; interface Access { }; }; #endifSince the
Administrator
should be able to do the same things as theCommonUser
, the previous inherits from the latter. TheAccess
interface will grant access to the DB. Now we are ready to define the functionality and data types we need. But, this requires that we know a little bit more about the OMG IDL.
The OMG defines a set of reserved case insensitive key-words, which may NOT be used as identifiers (e.g. module name). For more information, see Reserved Compiler Names and Keywords
6.4 Basic OMG IDL Types
The OMG IDL mapping is strongly typed and, even if you have a good knowledge of CORBA types, it is essential to read carefully the following mapping to Erlang types.
The mapping of basic types is straightforward. Note that the OMG IDL double type is mapped to an Erlang float which does not support the full double value range.
OMG IDL type Erlang type Note float Erlang float double Erlang float value range not supported short Erlang integer -2^15 .. 2^15-1 unsigned short Erlang integer 0 .. 2^16-1 long Erlang integer -2^31 .. 2^31-1 unsigned long Erlang integer 0 .. 2^32-1 long long Erlang integer -2^63 .. 2^63-1 unsigned long long Erlang integer 0 .. 2^64-1 char Erlang integer ISO-8859-1 wchar Erlang integer UTF-16 (ISO-10646-1:1993) boolean Erlang atom true/false octet Erlang integer any Erlang record #any{typecode, value} long double Not supported Object Orber object reference Internal Representation void Erlang atom ok OMG IDL basic types The
any
value is written as a record with the field typecode which contains the Type Code representation, see also the Type Code table, and the value field itself.Functions with return type
void
will return the atomok
.6.5 Template OMG IDL Types and Complex Declarators
Constructed types all have native mappings as shown in the table below.
Type IDL code Maps to Erlang code string typedef string S;
void op(in S a);Erlang string ok = op(Obj, "Hello World"), wstring typedef wstring S;
void op(in S a);Erlang list of Integers ok = op(Obj, "Hello World"), sequence typedef sequence <long, 3> S;
void op(in S a);Erlang list ok = op(Obj, [1, 2, 3]), array typedef string S[2];
void op(in S a);Erlang tuple ok = op(Obj, {"one", "two"}), fixed typedef fixed<3,2> myFixed;
void op(in myFixed a);Erlang tuple MF = fixed:create(3, 2, 314),
ok = op(Obj, MF),OMG IDL Template and Complex Declarators 6.5.1 String/WString Data Types
A
string
consists of all possible 8-bit quantities except null. Most ORB:s uses, including Orber, the character set Latin-1 (ISO-8859-1). Thewstring
type is represented as a list of integers, where each integer represents a wide character. In this case Orber uses, as most other ORB:s, the UTF-16 (ISO-10646-1:1993) character set.When defining a a string or wstring they can be of limited length or null terminated:
// Null terminated typedef string myString; typedef wstring myWString; // Maximum length 10 typedef string<10> myString10; typedef wstring<10> myWString10;If we want to define a char/string or wchar/wstring constant, we can use octal (\OOO - one, two or three octal digits), hexadecimal (\xHH - one or two hexadecimal digits) and unicode (\uHHHH - one, two, three or four hexadecimal digits.) representation as well. For example:
const string SwedensBestSoccerTeam = "\101" "\x49" "\u004B"; const wstring SwedensBestHockeyTeam = L"\101\x49\u004B"; const char aChar = '\u004B'; const wchar aWchar = L'\u004C';Naturally, we can use
"Erlang"
,L"Rocks"
,'A'
andL'A'
as well.6.5.2 Sequence Data Type
A sequence can be defined to be of a maximum length or unbounded, and may contain Basic and Template types and scoped names:
typedef sequence <short, 1> aShortSequence; typedef sequence <long> aLongSequence; typedef sequence <aLongSequence> anEvenLongerSequence;6.5.3 Array Data Type
Arrays are multidimensional, fixed-size arrays. The indices is language mapping specific, which is why one should not pass them as arguments to another ORB.
typedef long myMatrix[2][3];6.5.4 Fixed Data Type
A Fixed Point literal consists of an integer part (decimal digits), decimal point and a fraction part (decimal digits), followed by a
D
ord
. Either the integer part or the fraction part may be missing; the decimal point may be missing, but not d/D. The integer part must be a positive integer less than 32. The Fraction part must be a positive integer less than or equal to the Integer part.const fixed myFixed1 = 3.14D; const fixed myFixed2 = .14D; const fixed myFixed3 = 0.14D; const fixed myFixed4 = 3.D; const fixed myFixed5 = 3D;It is also possible to use unary (+-) and binary (+-*/) operators:
const fixed myFixed6 = 3D + 0.14D; const fixed myFixed7 = -3.14D;The Fixed Point examples above are, so called, anonymous definitions. In later CORBA specifications these have been deprecated as function parameters or return values. Hence, we strongly recommend that you do not use them. Instead, you should use:
typedef fixed<5,3> myFixed53; const myFixed53 myFixed53constant = 03.140d; typedef fixed<3,2> myFixed32; const myFixed32 myFixed32constant = 3.14d; myFixed53 foo(in myFixed32 MF); // OK void bar(in fixed<5,3> MF); // IllegalFor more information, see Fixed in Orber's Reference Manual.
Now we continue to work on our IDL specification. To begin with, we want to limit the size of the logon parameters (Id and password). Since the
UserID
andPassword
paremeters, only will be used when invoking operations on theAccess
interface, we may choose to define them within the scope that interface. To keep it simple our DB will contain employee information. Hence, as the DB key we choose an integer (EmployeeNo
).// DB IDL #ifndef _DB_IDL_ #define _DB_IDL_ module DB { typedef unsigned long EmployeeNo; interface CommonUser { any lookup(in EmployeeNo Name); }; interface Administrator : CommonUser { void delete(in EmployeeNo Name); }; interface Access { typedef string<10> UserID; typedef string<10> Password; CommonUser logon(in UserID ID, in Password PW); }; }; #endifBut what should, for example, the
lookup
operation return? One option is to use theany
data type. But, depending on what kind of data it encapsulates, this datatype can be rather expensive to use. We might find a solution to our problems among theConstructed
IDL types.6.6 Constructed OMG IDL Types
Constructed types all have native mappings as shown in the table below.
Type IDL code Maps to Erlang code struct struct myStruct {
long a;
short b;
};
void op(in myStruct a);Erlang record ok = op(Obj, #'myStruct'{a=300, b=127}), union union myUnion switch(long) {
case 1: long a;
};
void op(in myUnion a);Erlang record ok = op(Obj, #'myUnion'{label=1, value=66}), enum enum myEnum {one, two};
void op(in myEnum a);Erlang atom ok = op(Obj, one), OMG IDL constructed types 6.6.1 Struct Data Type
A
struct
may have Basic, Template, Scoped Names and Constructed types as members.6.6.2 Enum Data Type
The maximum number of identifiers which may defined in an enumeration is 2³². The order in which the identifiers are named in the specification of an enumeration defines the relative order of the identifiers.
6.6.3 Union Data Type
A
union
may consist of:
- Identifier
- Switch - may be an integer, char, boolean, enum or scoped name.
- Body - with or without a
default
case; may appear at most once.
A case label must match the defined type of the discriminator, and may only contain a default case if the values given in the non-default labels do not cover the entire range of the union's discriminant type. For example:
// Illegal default; all cases covered by // non-default cases. union BooleanUnion switch(boolean) { case TRUE: long TrueValue; case FALSE: long FalseValue; default: long DefaultValue; }; // OK union BooleanUnion2 switch(boolean) { case TRUE: long TrueValue; default: long DefaultValue; };It is not necessary to list all possible values of the union discriminator in the body. Hence, the value of a union is the value of the discriminator and, in given order, one of the following:
- If the discriminator match a label, explicitly listed in a case statement, the value must be of the same type.
- If the union contains a default label, the value must match the type of the default label.
- No value. Orber then inserts the Erlang atom
undefined
in the value field when receiving a union from an external ORB.
The above can be summed up to:
// If the discriminator equals 1 or 2 the value // is a long. Otherwise, the atom undefined. union LongUnion switch(long) { case 1: case 2: long TrueValue; }; // If the discriminator equals 1 or 2 the value // is a long. Otherwise, a boolean. union LongUnion2 switch(long) { case 1: case 2: long TrueValue; default: boolean DefaultValue; };
Every field in, for example, a struct must be initiated. Otherwise it will be set to the atom
undefined
, which Orber cannot encode when communicating via IIOP. In the example above, invoking the opertion with #'myStruct'{a=300} will fail (equal to #'myStruct'{a=300, b=undefined})Now we can continue to work on our IDL specification. To begin with, we should determine the return value of the
lookup
operation. Since theany
type can be rather expensive we can use astruct
or aunion
instead. If we intend to return the same information about a employee every time we can use a struct. Let us assume that the DB contains the name, address, employee number and department.// DB IDL #ifndef _DB_IDL_ #define _DB_IDL_ module DB { typedef unsigned long EmployeeNo; enum Department {Department1, Department2}; struct employee { string Name; string Address; Department Dpt; EmployeeNo No; }; typedef employee EmployeeData; interface CommonUser { EmployeeData lookup(in EmployeeNo Name); }; interface Administrator : CommonUser { void delete(in EmployeeNo Name); }; interface Access { typedef string<10> UserID; typedef string<10> Password; // Since Administrator inherits from CommonUser // the returned Object can be of either type. CommonUser logon(in UserID ID, in Password PW); }; }; #endifWe can also define exceptions (i.e. not system exception) thrown by each interface. Since exceptions are thoroughly described in the chapter System and User Defined Exceptions, we choose not to. Hence, we are now ready to compile our IDL-file by invoking:
$ erlc DB.idlor:
$ erl Erlang (BEAM) emulator version 5.1.1 [threads:0] Eshell V5.1.1 (abort with ^G) 1> ic:gen('DB'). ok 2> halt().The next step is to implement our servers. But, to be able to do that, we need to know how we can access data type definitions. For example, since a struct is mapped to an Erlang record we must include an hrl-file in our callback module.
6.7 Scoped Names and Generated Files
6.7.1 Scoped Names
Within a scope all identifiers must be unique. The following kinds of definitions form scopes in the OMG IDL:
- module
- interface
- operation
- valuetype
- struct
- union
- exception
For example, since enumerants do not form a scope, the following IDL code is not valid:
module MyModule { // 'two' is not unique enum MyEnum {one, two}; enum MyOtherEnum {two, three}; };But, since Erlang only has two levels of scope, module and function, the OMG IDL scope is mapped as follows:
- Function Scope - used for constants, operations and attributes.
- Erlang Module Scope - the Erlang module scope handles the remaining OMG IDL scopes.
An Erlang module, corresponding to an IDL global name, is derived by converting occurencies of "::" to underscore, and eliminating the leading "::". Hence, accessing
MyEnum
from another module, one useMyModule::MyEnum
For example, an operation
foo
defined in interfaceI
, which is defined in moduleM
, would be written in IDL asM::I::foo
and as'M_I':foo
in Erlang -foo
is the function name and'M_I'
is the name of the Erlang module. Applying this knowledge to a stripped version of the DB.idl gives:// DB IDL #ifndef _DB_IDL_ #define _DB_IDL_ // ++ topmost scope ++ // IC generates oe_XX.erl and oe_XX.hrl. // XX is equal to the name of the IDL-file. // Tips: create one IDL-file for each top module // and give the file the same name (DB.idl). // The oe_XX.erl module is used to register data // in the IFR. module DB { // ++ Module scope ++ // To access 'EmployeeNo' from another scope, use: // DB::EmployeeNo, DB::Access etc. typedef unsigned long EmployeeNo; enum Department {Department1, Department2}; // Definitions of this struct is contained in: // DB.hrl // Access functions exported by: // DB_employee.erl struct employee { ... CUT ... }; typedef employee EmployeeData; ... CUT ... // If this interface should inherit an interface // in another module (e.g. OtherModule) use: // interface Access : OtherModule::OtherInterface interface Access { // ++ interface scope ++ // Types within this scope is accessible via: // DB::Access::UserID // The Stub/Skeleton for this interface is // placed in the module: // DB_Access.erl typedef string<10> UserID; typedef string<10> Password; // Since Administrator inherits from CommonUser // the returned Object can be of either type. // This operation is exported from: // DB_Access.erl CommonUser logon(in UserID ID, in Password PW); }; }; #endifUsing underscores in IDL names can lead to ambiguities due to the name mapping described above. It is advisable to avoid the use of underscores in identifiers. For example, the following definition would generate two structures namned
x_y_z
.module x { struct y_z { ... }; interface y { struct z { ... }; }; };6.7.2 Generated Files
Several files can be generated for each scope.
- An Erlang source code file (
.erl
) is generated for top level scope as well as the Erlang header file.
- An Erlang header file (
.hrl
) will be generated for each scope. The header file will contain record definitions for allstruct
,union
andexception
types in that scope.
- Modules that contain at least one constant definition, will produce Erlang source code files (
.erl
). That Erlang file will contain constant functions for that scope. Modules that contain no constant definitions are considered empty and no code will be produced for them, but only for their included modules/interfaces.
- Interfaces will produce Erlang source code files (
.erl
), this code will contain all operation stub code and implementation functions.
- In addition to the scope-related files, an Erlang source file will be generated for each definition of the types
struct
,union
andexception
(these are the types that will be represented in Erlang as records). This file will contain special access functions for that record.
- The top level scope will produce two files, one header file (
.hrl
) and one Erlang source file (.erl
). These files are named as the IDL file, prefixed withoe_
.
After compiling DB.idl, the following files have been generated:
oe_DB.hrl
andoe_DB.erl
for the top scope level.
DB.hrl
for the moduleDB
.
DB_Access.hrl
andDB_Access.erl
for the interfaceDB_Access
.
DB_CommonUser.hrl
andDB_CommonUser.erl
for the interfaceDB_CommonUser
.
DB_Administrator.hrl
andDB_Administrator.erl
for the interfaceDB_Administrator
.
DB_employee.erl
for the structureemployee
in moduleDB
.
Since the
employee
struct is defined in the top level scope, the Erlang record definition is found inDB.hrl
. IC also generates stubs/skeletons (e.g.DB_CommonUser.erl
) and access functions for some datatypes (e.g.DB_employee.erl
). How the stubs/skeletons are used is thoroughly described in Stubs/Skeletons and Module_Interface.6.8 Typecode, Identity and Name Access Functions
As mentioned in a previous section,
struct
,union
andexception
types yield record definitions and access code for that record. Forstruct
,union
,exception
,array
andsequence
types, a special file is generated that holds access functions forTypeCode
,Identity
andName
. These functions are put in the file corresponding to the scope where they are defined. For example, the moduleDB_employee.erl
, representing theemployee
struct, exports the following functions:
- tc/0 - returns the type code for the struct.
- id/0 - returns the IFR identity of the struct. In this case the returned value is
"IDL:DB/employee:1.0"
, but if the struct was defined in the scope ofCommonUser
, the result would be"IDL:DB/CommonUser/employee:1.0"
. However, the user usually do not need to know the Id, just which Erlang module contains the correct Id.
- name/0 - returns the scoped name of the struct. The
employee
struct name is"DB_employee"
.
Type Codes are, for example, used in Any values. Hence, we can encapsulate the
employee
struct in anany
type by:%% Erlang code .... AnEmployee = #'DB_employee'{'Name' = "Adam Ivan Kendall", 'Address' = "Rasunda, Solna", 'Dpt' = 'Department1', 'No' = 1}, EmployeeTC = 'DB_employee':tc(), EmployeeAny = any:create(EmployeeTC, AnEmployee), ....For more information, see the Type Code listing.
6.9 References to Constants
Constants are generated as Erlang functions, and are accessed by a single function call. The functions are put in the file corresponding to the scope where they are defined. There is no need for an object to be started to access a constant.
Example:
// m.idl module m { const float pi = 3.14; interface i { const float pi = 3.1415; }; };Since the two constants are defined in different scopes, the IDL code above is valid, but not necessarily a good approach. After compiling
m.idl
, the constant definitions can be extracted by invoking:$ erlc m.idl $ erlc m.erl $ erl Erlang (BEAM) emulator version 5.1.1 [threads:0] Eshell V5.1.1 (abort with ^G) 1> m:pi(). 3.14000 2> m_i:pi(). 3.14150 3> halt().6.10 References to Objects Defined in OMG IDL
Objects are accessed by object references. An object reference is an opaque Erlang term created and maintained by the ORB.
Objects are implemented by providing implementations for all operations and attributes of the Object, see operation implementation.
6.11 Exceptions
Exceptions are handled as Erlang catch and throws. Exceptions are translated to messages over an IIOP bridge but converted back to a throw on the receiving side. Object implementations that invoke operations on other objects must be aware of the possibility of a non-local return. This includes invocation of ORB and IFR services. See also the Exceptions section.
Exception parameters are mapped as an Erlang record and accessed as such.
An object implementation that raises an exception will use the
corba:raise/1
function, passing the exception record as parameter.6.12 Access to Attributes
Attributes are accessed through their access functions. An attribute implicitly defines the
_get
and_set
operations. These operations are handled in the same way as normal operations. The_get
operation is defined as areadonly
attribute.readonly attribute long RAttribute; attribute long RWAttribute;The
RAttribute
requires that you implement, in your call-back module,_get_RAttribute
. For theRWAttribute
it is necessary to implement_get_RWAttribute
and_set_RWAttribute
.6.13 Invocations of Operations
A standard Erlang
gen_server
behavior is used for object implementation. Thegen_server
state is then used as the object internal state. Implementation of the object function is achieved by implementing its methods and attribute operations. These functions will usually have the internal state as their first parameter, followed by anyin
andinout
parameters.Do not confuse the object internal state with its object reference. The object internal state is an Erlang term which has a format defined by the user.
It is is not always the case that the internal state will be the first parameter, as stubs can use their own object reference as the first parameter (see the IC documentation).
A function call will invoke an operation. The first parameter of the function should be the object reference and then all
in
andinout
parameters follow in the same order as specified in the IDL specification. The result will be a return value unless the function hasinout
orout
parameters specified; in which case, a tuple of the return value, followed by the parameters will be returned.Example:
// IDL module m { interface i { readonly attribute long RAttribute; attribute long RWAttribute; long foo(in short a); long bar(in char c, inout string s, out long count); void baz(out long Id); }; };Is used in Erlang as :
%% Erlang code .... Obj = ... %% get object reference RAttr = m_i:'_get_RAttribute'(Obj), RWAttr = m_i:'_get_RWAttribute'(Obj), ok = m_i:'_set_RWAttribute'(Obj, Long), R1 = m_i:foo(Obj, 55), {R2, S, Count} = m_i:bar(Obj, $a, "hello"), ....Note how the
inout
parameter is passed and returned. There is no way to use a single occurrence of a variable for this in Erlang. Also note, thatok
, Orber's representation of the IDL-typevoid
, must be returned bybaz
and'_set_RWAttribute'
. These operations can be implemented in the call-back module as:'_set_RWAttribute'(State, Long) -> {reply, ok, State}. '_get_RWAttribute'(State) -> {reply, Long, State}. '_get_RAttribute'(State) -> {reply, Long, State}. foo(State, AShort) -> {reply, ALong, State}. bar(State, AShort, AString) -> {reply, {ALong, "MyString", ALong}, State}. baz(State) -> {reply, {ok, AId}, State}.The operations may require more arguments (depends on IC options used). For more information, see Stubs/Skeletons and Module_Interface.
A function can also be defined to be
oneway
, i.e. asynchronous. But, since the behavior of a oneway operation is not defined in the OMG specifications (i.e. the behavior can differ depending on which other ORB Orber is communicating with), one should avoid using it.6.14 Implementing the DB Application
Now we are ready to implement the call-back modules. There are three modules we must create:
- DB_Access_impl.erl
- DB_CommonUser_impl.erl
- DB_Administrator_impl.erl
We begin to implement the
DB_Access_impl.erl
module:-module('DB_Access_impl'). %% Mandatory -export([init/1, terminate/2, code_change/3]). %% Interface functions -export([logon/3]). init(Env) -> %% Usually we use the Env parameter create a State %% but that is not in the scope of this example. {ok, Env}. terminate(Reason, State) -> %% Here we clean up before terminating. ok. code_change(OldVsn, State, Extra) -> {ok, State}. logon(State, Id, Pwd) -> %% Check if the Id/Pwd is valid and what %% type of user it is (Common or Administrator). Obj = case check_user(Id, Pwd) of {ok, administrator} -> 'DB_Administrator':oe_create(); {ok, common} -> 'DB_CommonUser':oe_create(); error -> %% Here we should throw an exception corba:raise(....) end, {reply, Obj, State}.Since
DB_Administrator
inherits fromDB_CommonUser
, we must implementdelete
in theDB_Administrator_impl.erl
module, andlookup
inDB_Administrator_impl.erl
andDB_CommonUser_impl.erl
. But wait, is that really necessary? Actually, it is not. We simple use the IC compile option impl:$ erlc +'{{impl, "DB::CommonUser"}, "DBUser_impl"}' +'{{impl, "DB::Administrator"}, "DBUser_impl"}' DB.idl $ erlc *.erlInstead of creating, and not the least, maintaining two call-back modules, we only have to deal with
DBUser_impl.erl
. See also the Exceptions chapter. In the following example, the mandatory functions are left out:-module('DBUser_impl'). %% Interface functions -export([delete/2, lookup/2]). %% How we access the DB, for example mnesia, is not shown here. lookup(State, No) -> case lookup_employee(No) of %% We assume that we receive a 'DB_employee' struct {ok, Employee} -> {reply, Employee, State}. error -> %% Here we should throw an exception if %% there is no match. corba:raise(....) end. delete(State, No) -> case delete_employee(No) of ok -> {reply, ok, State}. error -> %% Here we should throw an exception if %% there is no match. corba:raise(....) end.After you have compiled both call-back modules, and implemented the missing functionality (e.g. lookup_employee/1), we can test our application:
%% Erlang code .... %% Create an Access object Acc = 'DB_Access':oe_create(), %% Login is Common user and Administrator Adm = 'DB_Access':logon(A, "admin", "pw"), Com = 'DB_Access':logon(A, "comm", "pw"), %% Lookup existing employee Employee = 'DB_Administrator':lookup(Adm, 1), Employee = 'DB_CommonUser':lookup(Adm, 1), %% If we try the same using the DB_CommonUser interface %% it result in an exit since that operation is not exported. {'EXIT', _} = (catch 'DB_CommonUser':delete(Adm, 1)), %% Try to delete the employee via the CommonUser Object {'EXCEPTION', _} = (catch 'DB_Administrator':delete(Com, 1)), %% Invoke delete operation on the Administrator object ok = 'DB_Administrator':delete(Adm, 1), ....6.15 Reserved Compiler Names and Keywords
The use of some names is strongly discouraged due to ambiguities. However, the use of some names is prohibited when using the Erlang mapping , as they are strictly reserved for IC.
IC reserves all identifiers starting with
OE_
andoe_
for internal use.Note also, that an identifier in IDL can contain alphabetic, digits and underscore characters, but the first character must be alphabetic.
The OMG defines a set of reserved words, shown below, for use as keywords. These may not be used as, for example, identifiers. The keywords which are not in bold face was introduced in the OMG CORBA-3.0 specification.
abstract exception inout provides truncatable any emits interface public typedef attribute enum local publishes typeid boolean eventtype long raises typeprefix case factory module readonly unsigned char FALSE multiple setraises union component finder native sequence uses const fixed Object short ValueBase consumes float octet string valuetype context getraises oneway struct void custom home out supports wchar default import primarykey switch wstring double in private TRUE OMG IDL keywords The keywords listed above must be written exactly as shown. Any usage of identifiers that collide with a keyword is illegal. For example, long is a valid keyword; Long and LONG are illegal as keywords and identifiers. But, since the OMG must be able to expand the IDL grammar, it is possible to use Escaped Identifiers. For example, it is not unlikely that
native
have been used in IDL-specifications as identifiers. One option is to change all occurances tomyNative
. Usually, it is necessary to change programming language code that depends upon that IDL as well. Since Escaped Identifiers just disable type checking (i.e. if it is a reserved word or not) and leaves everything else unchanged, it is only necessary to update the IDL-specification. To escape an identifier, simply prefix it with _. The following IDL-code is illegal:typedef string native; interface i { void foo(in native Arg); }; };With Escaped Identifiers the code will look like:
typedef string _native; interface i { void foo(in _native Arg); }; };6.16 Type Code Representation
Type Codes are used in
any
values. To avoid mistakes, you should use access functions exported by the Data Types modules (e.g. struct, union etc) or the orber_tc module.
Type Code Example tk_null tk_void tk_short tk_long tk_longlong tk_ushort tk_ulong tk_ulonglong tk_float tk_double tk_boolean tk_char tk_wchar tk_octet tk_any tk_TypeCode tk_Principal {tk_objref, IFRId, Name} {tk_objref, "IDL:M1\I1:1.0", "I1"} {tk_struct, IFRId, Name, [{ElemName, ElemTC}]} {tk_struct, "IDL:M1\S1:1.0", "S1", [{"a", tk_long}, {"b", tk_char}]} {tk_union, IFRId, Name, DiscrTC, DefaultNr, [{Label, ElemName, ElemTC}]}
Note: DefaultNr tells which of tuples in the case list that is default, or -1 if no default{tk_union, "IDL:U1:1.0", "U1", tk_long, 1, [{1, "a", tk_long}, {default, "b", tk_char}]} {tk_enum, IFRId, Name, [ElemName]} {tk_enum, "IDL:E1:1.0", "E1", ["a1", "a2"]} {tk_string, Length} {tk_string, 5} {tk_wstring, Length} {tk_wstring, 7} {tk_fixed, Digits, Scale} {tk_fixed, 3, 2} {tk_sequence, ElemTC, Length} {tk_sequence, tk_long, 4} {tk_array, ElemTC, Length} {tk_array, tk_char, 9} {tk_alias, IFRId, Name, TC} {tk_alias, "IDL:T1:1.0", "T1", tk_short} {tk_except, IFRId, Name, [{ElemName, ElemTC}]} {tk_except, "IDL:Exc1:1.0", "Exc1", [{"a", tk_long}, {"b", {tk_string, 0}}]} Type Code tuples