Next: The Dynamic Invocation Up: No Title Previous: Type Any and

# Dynamic Management of Any Values

In CORBA specification 2.2, a new facility- DynAny is introduced. Previously, it is not possible to insert or extract constructed and other complex types from an any without using the stub code generated by an idl compiler for these types. This makes it impossible to write generic servers (bridges, event channels supporting filtering etc) because these servers can not have static knowledge of all the possible data types that they have to handle.

To fill this gap, the DynAny facility is defined to enable traversal of the data value associated with an any at runtime and extraction of its constituents. This facility also enables the construction of an any at runtime, without having static knowledge of its types.

This chapter explains how DynAny may be used. For completeness, you should also read the DynAny specification defined in Chapter 7 of the CORBA specification 2.2. Where possible, the implementation in omniORB2 adheres closely to the specification. However, there are areas in the specification that are ambiguous or lacking in details. A number of these issues are currently opened with the ORB revision task force. Until the issues are resolved, it is possible that a different implementation may choose to intepret the specification differently. This chapter provides clarifications to the specification, explains the interpretation used and offers some advice and warnings on potential portability problems.

# C++ mapping

      // namespace CORBA

      class ORB {
      public:
        ...

        class InconsistentTypeCode : public UserException { ... };

        DynAny_ptr create_dyn_any(const Any& value);

        DynAny_ptr create_basic_dyn_any(TypeCode_ptr tc);

        DynStruct_ptr create_dyn_struct(TypeCode_ptr tc);

        DynSequence_ptr create_dyn_sequence(TypeCode_ptr tc);

        DynArray_ptr create_dyn_array(TypeCode_ptr tc);

        DynUnion_ptr create_dyn_union(TypeCode_ptr tc);

        DynEnum_ptr create_dyn_enum(TypeCode_ptr tc);

      };

      typedef DynAny* DynAny_ptr;
      class DynAny_var { ... };

      class DynAny {
      public:

        class Invalid : public UserException { ... };
        class InvalidValue : public UserException { ... };
        class TypeMismatch : public UserException { ... };
        class InvalidSeq : public UserException { ... };

        typedef _CORBA_Unbounded_Sequence__Octet OctetSeq;

        TypeCode_ptr type() const;

        void assign(DynAny_ptr dyn_any) throw(Invalid,SystemException);
        void from_any(const Any& value) throw(Invalid,SystemException);
        Any* to_any() throw(Invalid,SystemException);
        void destroy();
        DynAny_ptr copy();

        DynAny_ptr current_component();
        Boolean next();
        Boolean seek(Long index);
        void rewind();

        void insert_boolean(Boolean value) throw(InvalidValue,SystemException);
        void insert_octet(Octet value) throw(InvalidValue,SystemException);
        void insert_char(Char value) throw(InvalidValue,SystemException);
        void insert_short(Short value) throw(InvalidValue,SystemException);
        void insert_ushort(UShort value) throw(InvalidValue,SystemException);
        void insert_long(Long value) throw(InvalidValue,SystemException);
        void insert_ulong(ULong value) throw(InvalidValue,SystemException);
        void insert_float(Float value) throw(InvalidValue,SystemException);
        void insert_double(Double value) throw(InvalidValue,SystemException);
        void insert_string(const char* value) throw(InvalidValue,SystemException);
        void insert_reference(Object_ptr v) throw(InvalidValue,SystemException);
        void insert_typecode(TypeCode_ptr v) throw(InvalidValue,SystemException);
        void insert_any(const Any& value) throw(InvalidValue,SystemException);

        Boolean get_boolean() throw(TypeMismatch,SystemException);
        Octet get_octet() throw(TypeMismatch,SystemException);
        Char get_char() throw(TypeMismatch,SystemException);
        Short get_short() throw(TypeMismatch,SystemException);
        UShort get_ushort() throw(TypeMismatch,SystemException);
        Long get_long() throw(TypeMismatch,SystemException);
        ULong get_ulong() throw(TypeMismatch,SystemException);
        Float get_float() throw(TypeMismatch,SystemException);
        Double get_double() throw(TypeMismatch,SystemException);
        char* get_string() throw(TypeMismatch,SystemException);
        Object_ptr get_reference() throw(TypeMismatch,SystemException);
        TypeCode_ptr get_typecode() throw(TypeMismatch,SystemException);
        Any* get_any() throw(TypeMismatch,SystemException);

        static DynAny_ptr _duplicate(DynAny_ptr);
        static DynAny_ptr _narrow(DynAny_ptr);
        static DynAny_ptr _nil();
      };

      // DynFixed is not supported.

      typedef DynEnum* DynEnum_ptr;
      class DynEnum_var { ... };

      class DynEnum :  public DynAny {
      public:

        char* value_as_string();
        void value_as_string(const char* value);
        ULong value_as_ulong();
        void value_as_ulong(ULong value);

        static DynEnum_ptr _duplicate(DynEnum_ptr);
        static DynEnum_ptr _narrow(DynAny_ptr);
        static DynEnum_ptr _nil();
      };

      typedef char* FieldName;
      typedef String_var FieldName_var;

      struct NameValuePair {
        String_member id;
        Any value;
      };

      typedef _CORBA_ConstrType_Variable_Var<NameValuePair> NameValuePair_var;
      typedef _CORBA_Unbounded_Sequence<NameValuePair > NameValuePairSeq;

      typedef DynStruct* DynStruct_ptr;
      class DynStruct_var { ... };

      class DynStruct :  public DynAny {
      public:

        char*  current_member_name();
        TCKind current_member_kind();
        NameValuePairSeq* get_members();
        void set_members(const NameValuePairSeq& NVSeqVal)
                         throw(InvalidSeq,SystemException);

        static DynStruct_ptr _duplicate(DynStruct_ptr);
        static DynStruct_ptr _narrow(DynAny_ptr);
        static DynStruct_ptr _nil();
      };

      typedef DynUnion* DynUnion_ptr;
      class DynUnion_var { ... };

      class DynUnion :  public DynAny {
      public:

        Boolean set_as_default();
        void set_as_default(Boolean value);
        DynAny_ptr discriminator();
        TCKind discriminator_kind();
        DynAny_ptr member();
        char*  member_name();
        void member_name(const char* value);
        TCKind member_kind();

        static DynUnion_ptr _duplicate(DynUnion_ptr);
        static DynUnion_ptr _narrow(DynAny_ptr);
        static DynUnion_ptr _nil();
      };

      typedef _CORBA_Unbounded_Sequence<Any > AnySeq;

      typedef DynSequence* DynSequence_ptr;
      class DynSequence_var { ... };

      class DynSequence :  public DynAny {
      public:

        ULong length();
        void length (ULong value);
        AnySeq* get_elements();
        void set_elements(const AnySeq& value) throw(InvalidValue,SystemException);

        static DynSequence_ptr _duplicate(DynSequence_ptr);
        static DynSequence_ptr _narrow(DynAny_ptr);
        static DynSequence_ptr _nil();
      };

      typedef DynArray* DynArray_ptr;
      class DynArray_var { ... };

      class DynArray : public DynAny {
      public:

        AnySeq* get_elements();
        void set_elements(const AnySeq& value) throw(InvalidValue,SystemException);

        static DynArray_ptr _duplicate(DynArray_ptr);
        static DynArray_ptr _narrow(DynAny_ptr);
        static DynArray_ptr _nil();
      };

# The DynAny Interface

## Example: extract data values from an Any

If an any contains a value of one of the basic data types, its value can be extracted using the pre-defined operators in the Any interface. When the value is a struct or other non-basic types, one can use the DynAny interface to extract its constituent values.

In this section, we use a struct as an example to illustrate how the DynAny interface can be used.

The example struct is as follows:

        // IDL

        struct exampleStruct1 {
          string s;
          double d;
          long   l;
        };

To create a DynAny from an Any value, one uses the `create_dyn_any` method:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        Any v;
        ...       // Initialise v to contain a value of type exampleStruct1.

        CORBA::DynAny_var dv = orb->create_dyn_any(v);

Like CORBA object and pseudo object references, a `DynAny_ptr` can be managed by a _var type (`DynAny_var`) which will release the `DynAny_ptr` automatically when the variable goes out of scope.

### Iterate through the components

Once the DynAny object is created, we can use the DynAny interface to extract the individual components in `exampleStruct1`. The DynAny interface provides a number of functions to extract and insert component values. These functions are defined to operate on the component identified by the current component pointer.

A current component pointer is an internal state of a DynAny object. When a DynAny object is created, the pointer is initialised to point to the first component of the any value.

The pointer can be advanced to the next component with the `next()` operation. The function returns FALSE (0) if there are no more components. Otherwise it returns TRUE (1). When the any value in the DynAny object contains only one component, the `next()` operation always returns FALSE(0).

Another way of adjusting the pointer is the `seek()` operation. The function returns FALSE (0) if there is no component at the specified index. Otherwise it returns TRUE (1). The index value of the first component is zero. Therefore, a `seek(0)` call rewinds the pointer to the first component, this is also equivalent to a call to the `rewind()` operation.

For completeness, we should also mention here the `current_component()` operation. This operation causes the DynAny object to return a reference to another DynAny object that can be used to access the current component. It is possible that the current component pointer is not pointing to a valid component, for instance, the `next()` operation has been invoked and there is no more component. Under this circumstance, the `current_component()` operation returns a nil DynAny object reference. For components which are just basic data types, calling `current_component()` is an overkill because we can just use the basic type extraction and insertion functions directly.

### Extract basic type components

In our example, the component values can be extracted as follows:

        CORBA::String_var s = dv->get_string();
        CORBA::Double     d = dv->get_double();
        CORBA::Long       l = dv->get_long();

Each get basic type operation has the side-effect of advancing the current component pointer. For instance:

        CORBA::String_var s = dv->get_string();

is equivalent to:

        CORBA::DynAny_var temp = dv->current_component();
        CORBA::String_var s = temp->get_string();
        dv->next();

The get operations ensure that the current component is of the same type as requested. Otherwise, the object throws a TypeMismatch exception. If the current component pointer is invalid when a get operation is called, the object also throws a TypeMismatch exception.

To repeatedly access the components, one can use the `rewind()` or `seek()` operation to manipulate the current component pointer. For instance, to access the `d` member in `exampleStruct1` directly:

        dv->seek(1);          // position current component to member d.
        CORBA::Double     d = dv->get_double();

### Extract complex components

When a component is not one of the basic data types, it is not possible to extract its value using the get operations. Instead, a DynAny object has to be created from which the component is accessed.

Consider this example:

        // IDL

        struct exampleStruct2 {
          string m1;
          exampleStruct1 m2;
        };

In order to extract the data members within `m2` (of type `exampleStruct1`), we use `current_component()` as follows:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
        Any v;
        ...       // Initialise v to contain a value of type exampleStruct2.

        CORBA::DynAny_var dv = orb->create_dyn_any(v);

        CORBA::String_var m1 = dv->get_string();  // extract member m1
        CORBA::DynAny_var dm = dv->current_component(); // DynAny reference to m2
        CORBA::String_var s = dm->get_string();   // m2.s
        CORBA::Double     d = dm->get_double();   // m2.d
        CORBA::Long       l = dm->get_long();     // m2.l

### Clean-up

Now we finish off this example with a description on destroying DynAny objects. There are two points to remember:

1. A DynAny reference (`DynAny_ptr`) is like any CORBA object or psuedo object reference and should be handled in the same way. In particular, one has to call the `CORBA::release` operation to indicate that a DynAny reference will no longer be accessed. In the example, this is done automatically by `DynAny_var`.
2. A DynAny object and its references are separate entities, just as a CORBA object implementation and its object references are different entities. While `CORBA::release` will release any resource associated with a `DynAny_ptr`, one has to separately destroy the DynAny object to avoid any memory leak. This is done by calling the `destroy()` operation.

In the example, the DynAny object can be destroyed as follows:

        // C++
        ...
        CORBA::DynAny_var dv = orb->create_dyn_any(v);
        ...
        dv->destroy();

        // From now on, one should not invoke any operation in dv. Otherwise the
        // behavior is undefined.

## Example: insert data values into an Any

Using the DynAny interface, one can create an Any value from scratch. In this example, we are going to create an Any containing the value of the `exampleStruct1` type.

Firstly, we have to create a DynAny to store the value using one of the `create_dyn` functions. Because `exampleStruct1` is a struct type, we use the `create_dyn_struct()` operation.

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        // create the TypeCode for exampleStruct.
        StructMemberSeq tc_members;
        tc_members.length(3);
        tc_members[0].name = (const char*)"s";
        tc_members[0].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string);
        tc_members[0].type_def = CORBA::IDLType::_nil();
        tc_members[1].name = (const char*)"d";
        tc_members[1].type = CORBA::TypeCode::_duplicate(CORBA::_tc_double);
        tc_members[1].type_def = CORBA::IDLType::_nil();
        tc_members[2].name = (const char*)"l";
        tc_members[2].type = CORBA::TypeCode::_duplicate(CORBA::_tc_long);
        tc_members[2].type_def = CORBA::IDLType::_nil();
        CORBA::TypeCode_var tc = orb->create_struct_tc("IDL:exampleStruct1:1.0",
                                                       "exampleStruct1",
                                                       tc_members);

        // create the DynAny object to represent the any value
        CORBA::DynAny_var dv = orb->create_dyn_struct(tc);

### Insert basic type components

Once the DynAny object is created, we can use the DynAny interface to insert the components. The DynAny interface provides a number of insert operations to insert basic types into the any value. In our example, the component values can be inserted as follows:

        CORBA::String_var s = (const char*)"Hello";
        CORBA::Double     d = 3.1416;
        CORBA::Long       l = 1;

        dv->insert_string(s);
        dv->insert_double(d);
        dv->insert_long(l);

Each insert basic type operation has the side-effect of advancing the current component pointer. For instance:

        dv->insert_string(s);

is equivalent to:

        CORBA::DynAny_var temp = dv->current_component();
        temp->insert_string(s);
        dv->next();

The insert operations ensure that the current component is of the same type as the inserted value. Otherwise, the object throws a InvalidValue exception. If the current component pointer is invalid when an insert operation is called, the object also throws a InvalidValue exception.

Sometimes, one may just want to modify one component in an Any value. For instance, one may just want to change the value of the double member in `exampleStruct1`. This can be done as follows:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        Any v;
        ...       // Initialise v to contain a value of type exampleStruct1.

        CORBA::Double d = 6.28;

        CORBA::DynAny_var dv = orb->create_dyn_any(v);

        dv->seek(1);
        dv->insert_double(d);    // Change the value of the member d.

Finally, the any value can be obtained from the DynAny object using the `to_any()` operation:

        CORBA::Any_var v = dv->to_any();    // Obtain the any value.

### Insert complex components

When a component is not one of the basic data types, it is not possible to insert its value using the insert operations. Instead, a DynAny object has to be created through which the component can be inserted.

In our example, one can insert component values into `exampleStruct2` as follows:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        CORBA::TypeCode_var tc;
        // create the TypeCode for exampleStruct2.
        ...
        // create the DynAny object to represent the any value
        CORBA::DynAny_var dv = orb->create_dyn_struct(tc);

        CORBA::String_var m1  = (const char*)"Greetings";
        CORBA::String_var m2s = (const char*)"Hello";
        CORBA::Double     m2d = 3.1416;
        CORBA::Long       m2l = 1;

        dv->insert_string(m1);   // insert member m1
        CORBA::DynAny_var dm = dv->current_component(); // DynAny reference to m2
        dm->insert_string(m2s);  // insert member m2.s
        dm->insert_double(m2d);  // insert member m2.d
        dm->insert_long(m2l);    // insert member m2.l

        CORBA::Any_var v = dv->to_any();  // obtain the any value

        dv->destroy();          // destroy the DynAny object.
                                // No operation should be invoked on dv
                                // from this point on except CORBA::release.

In addition to the DynAny interface, a number of derived interfaces are defined. These interfaces are specialisation of the DynAny interface to facilitate the handling of any values containing non-basic types: struct, sequence, array, enum and union. The next few sections will provide more details on these interfaces.

# The DynStruct Interface

When a DynAny object is created through the `create_dyn_any()` operation and the any value contains a struct type, a DynStruct object is created. The DynAny reference returned can be narrowed to a DynStruct reference using the `CORBA::DynStruct::_narrow()` operation.

In the previous example, the components are extracted using the get operations. Alternatively, the DynStruct interface provides an addition operation (`get_members()`) to return all the components in a single call. The returned value is a sequence of name value pair. The member name is given in the name field and its value is returned as an Any value. For example, an alternative way to extract the components in the previous example is as follows:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
        Any v;
        ...       // Initialise v to contain a value of type exampleStruct1.
        CORBA::DynAny_var dv = orb->create_dyn_any(v);

        CORBA::DynStruct_var ds = CORBA::DynStruct::_narrow(dv);

        CORBA::NameValuePairSeq* sq = ds->get_members();

        char*         s;
        CORBA::Double d;
        CORBA::Long   l;

        (*sq)[0].value >>= s;        // 1st element contains member s
        (*sq)[1].value >>= d;        // 2nd element contains member d
        (*sq)[2].value >>= l;        // 3rd element contains member l

Similarly, the DynStruct interface provides an addition operation (`set_members()`) to insert all the components in a single call. The following is an alternative way to insert the components of the type `exampleStruct1` into an Any value:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        CORBA::TypeCode_var tc;
        // create the TypeCode for exampleStruct1.
        ...
        // create the DynAny object to represent the any value
        CORBA::DynAny_var dv = orb->create_dyn_struct(tc);

        CORBA::String_var s = (const char*)"Hello";
        CORBA::Double     d = 3.1416;
        CORBA::Long       l = 1;

        CORBA::NameValuePairSeq sq;
        sq.length(3);
        sq[0].id = (const char*)"s";
        sq[0].value <<= CORBA::Any::from_string(s,0);
                                        // 1st element contains member s
        sq[1].id = (const char*)"d";
        sq[1].value <<= d;             // 2nd element contains member d
        sq[2].id = (const char*)"l";
        sq[2].value <<= l;             // 3rd element contains member l

        dv->set_members(sq);

Notice that the name-value pairs in the argument to `set_members()` must match the members of the struct exactly or the object would throw the InvalidSeq exception.

In addition to the `current_component()` operation, the DynStruct interface provides two operations: `current_member_name()` and `current_member_kind()`, to return information about the current component.

# The DynSequence Interface

Like struct values, sequence values can be traversed using the operations introduced in section 10.2. The first sequence element can be accessed as the first DynAny component, the second sequence element as the second DynAny component and so on.

To extract component values from an Any containing a sequence, the length of the sequence can be obtained using the get length operation in the DynSequence interface. Here is an example to extract the components of a sequence of long:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
        Any v;
        ...       // Initialise v to contain a value of a sequence of long
        CORBA::DynAny_var dv = orb->create_dyn_any(v);

        CORBA::DynSequence_var ds = CORBA::DynSequence::_narrow(dv);
        CORBA::ULong len = ds->length();     // extract the length of the sequence
        CORBA::ULong index;
        for (index = 0; index < len; index++) {
          CORBA::Long v = ds->get_long();
          cerr << "[" << index << "] = " << v << endl;
        }

Conversely, the set length operation is provided to set the length of the sequence. Here is an example to insert the components of a sequence of long:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        CORBA::TypeCode_var tc;
        // create the TypeCode for a sequence of long.
        ...
        // create the DynAny object to represent the any value
        CORBA::DynSequence_var ds = orb->create_dyn_sequence(tc);

        CORBA::ULong len = 3;

        ds->length(len);             // set the length of the sequence

        CORBA::ULong index;
        for (index = 0; index < len; index++) {
          ds->insert_long(index);    // insert a sequence element
        }

Similar to the DynStruct interface, the `get_elements()` operation is provided to return all the sequence elements and the `set_elements()` operation is provided to insert all the sequence elements.

# The DynArray Interface

Array values are handled by the DynArray interface. The DynArray interface is the same as the DynSequence interface except that the former does not provide the set length and get length operations.

# The DynEnum Interface

Enum values are handled by the DynEnum interface. A DynEnum object contains a single component which is the enum value. This value cannot be extracted or inserted using the get and insert operations of the DynAny interface. Instead, two pairs of operations are provided to handle this value.

The `value_as_string` operations allow the enum value to be extracted or inserted as a string. The `value_as_ulong` operations allow the enum value to be extracted or inserted as an unsigned long.

# The DynUnion Interface

Union values are handled by the DynUnion interface. Unfortunately, the CORBA 2.2 specification does not define the DynUnion interface in sufficent details to nail down its intended usage. In this section, we try to fill in the gaps and describe a sensible way to use the DynUnion interface. Where necessary, the semantics of the operations is clarified. It is possible that the behavior of this interface in another ORB is different from this implmentation. Where appropriate, we give warnings on usage that might cause problems with portability.

In relation to the current component pointer (10.2.1.1), a DynUnion object contains two components. The first component (with the index value equals 0) is the discriminator value, the second one is the member value. Therefore, one can use the `seek()` and `current_component()` operations to obtain a reference to the DynAny objects that handle the two components. However, it is better to use the operations defined in the DynUnion interface to manipulate these components as the semantics of the operations is easier to understand.

## Three Categories of Union

Before we continue, it is important to understand that unions can be classified into the following categories:

1. One that has a default branch defined in the IDL. This will be called explicit default union in the rest of this section.
2. One that has no default branch and not all the possible values of the discriminator type are covered by the branch labels in the IDL. This will be called implicit default union.
3. One that has no default branch but all the possible values of the discriminator type are covered. This will be called no default union.

Of the three categories, the implicit default union is interesting because by definition if the discriminator value is not equal to any of the branch labels, the union has no member. That is, the union value consists solely of the discriminator value.

## Example: extract data values from a union

### Explicit default union

Consider a union of the following type:

        // IDL

        union exampleUnion1 switch(boolean) {
        case TRUE: long l;
        default:   double d;
        };

The most straightforward way to extract the member value is as follows:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        Any v;
        ...       // Initialise v to contain a value of type exampleUnion1.

        CORBA::DynAny_var dv = orb->create_dyn_any(v);
        CORBA::DynUnion_var du = CORBA::DynUnion::_narrow(dv);

        CORBA::String_var di = du->member_name();
        CORBA::DynAny_var dm = du->member();

        if (strcmp((const char*)di,"l") == 0) {
          // branch label is TRUE
          CORBA::Long v = dm->get_long();
          cerr << "l = " << v << endl;
        }

        if (strcmp((const char*)di,"d") == 0) {
          // Is default branch
          CORBA::Double v = dm->get_double();
          cerr << "d = " << v << endl;
        }

In the example, the operation `member_name()` is used to determine which branch the union has been instantiated. The operation `member()` is used to obtain a reference to the DynAny object that handles the member.

Alternatively, the branch can be determined by reading the discriminator value:

        // C++

        CORBA::DynAny_var di = du->discriminator();
        CORBA::DynAny_var dm = du->member();

        CORBA::Boolean di_v = di->get_boolean();

        switch (di_v) {
        case 1:
          CORBA::Long v = dm->get_long();
          cerr << "l = " << v << endl;
          break;
        default:
          CORBA::Double v = dm->get_double();
          cerr << "d = " << v << endl;
        }

The operation `discriminator()` is used to obtain the value of the discriminator.

Finally, the third way to determine the branch is to test if the default is selected:

        // C++

        switch (dv->set_as_default()) {
        case 1:
          CORBA::Double v = dm->get_double();
          cerr << "d = " << v << endl;
          break;
        default:
          CORBA::Long v = dm->get_long();
          cerr << "l = " << v << endl;
        }

The operation `set_as_default()` returns TRUE (1) if the discriminator has been assigned a valid default value.

### Implicit default union

Consider a union of the following type:

        // IDL

        union exampleUnion2 switch(long) {
        case 1: long l;
        case 2: double d;
        };

This example is similar to the previous one but there is no default branch. The description above also applies to this example. However, the discriminator may be set to neither 1 nor 2. Under this condition, the implicit default is selected and the union value contains the discriminator only!

When the discriminator contains an implicit default value, one might ask what is the value returned by the `member_name()` and `member()` operation. Since there is no member in the union value, omniORB2 returns a null string and a nil DynAny reference respectively. This behavior is not specified in the CORBA 2.2 specification. To ensure that your application is portable, it is best to avoid calling these operations when the DynUnion object might contain an implicit default value.

### No default union

This is the last union category. For instance:

        // IDL

        union exampleUnion3 switch(boolean) {
        case TRUE: long l;
        case FALSE: double d;
        };

In this example, all the possible values of the discriminator are used as union labels. There is no default branch. The only difference between this category and the explicit default union is that the `set_as_default()` operation always returns FALSE (0).

## Example: insert data values into a union

Writing into a union involves selecting the union branch with the appropriate discriminator value and then writing the member value. There are three ways to set the discriminator value:

1. Use the `member_name()` write operation to specify the union branch by specifying the union member directly. This operation has the side effect of setting the discriminator to the label value of the branch.
2. Write the label value of a union branch into the DynAny object that handles the discriminator.
3. If the union has a default branch, either explicitly or implicitly, use the `set_as_default()` write operation to set the discriminator to a valid default value.

The following example shows the three ways of writing into a union:

        // C++

        CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.

        CORBA::TypeCode_var tc;
        // create the TypeCode for exampleUnion1.
        ...
        // create the DynAny object to represent the any value
        CORBA::DynUnion_var dv = orb->create_dyn_union(tc);

        CORBA::Any_var v;
        DynAny_ptr dm;

        // Use member_name to select the union branch
        dv->member_name("l");
        dm = dv->member();
        dm->insert_long(10);
        v = dv->to_any();          // transfer to an Any
        CORBA::release(dm);

        // Setting the discriminator value to select the union branch
        CORBA::DynAny_var di = dv->discriminator();
        di->insert_boolean(1);     // set discriminator to label TRUE
        dm = dv->member();
        dm->insert_long(20);
        v = dv->to_any();          // transfer to an Any
        CORBA::release(dm);

        // Use set_as_default to select the default union branch
        dv->set_as_default(1);
        dm = dv->member();
        dm->insert_double(3.14);
        v = dv->to_any();          // transfer to an Any
        CORBA::release(dm);

        dv->destroy();

### Ambiguous usage

1. When the discriminator is set to a different value, a different member branch is selected. Suppose the application has previously obtained a DynAny reference to a union member when it changes the discriminator value. As a result of the value change, the union is now instantiated to another union branch, i.e. a call to the `member()` operation will now return a reference to a different DynAny object. If the application continues to access the DynAny object of the old union member, the behavior of the ORB under this condition is not defined by the CORBA 2.2 specification. With omniORB2, the DynAny object of the old union member is detached from the union when a new union branch is selected. Therefore reading or writing this object will not have any relation to the current value of the union. To avoid this ambiguity, the reference to the old union member should be released before a different union branch is selected.

2. The write operation `set_as_default()` takes a boolean argument. It is ambiguous to call this function with the argument set to FALSE (0). With omniORB2, such a call will be silently ignored.

3. It is also ambiguous to pass the value TRUE (1) to the `set_as_default()` operation when the union is a no default union (10.7.1). With omniORB2, such a call will be silently ignored.

4. When the discriminator value is not set, calling the `member()` operation is ambiguous. With omniORB2, such a call will return a nil DynAny reference. Similarly, a call to the `member_kind()` operation under this condition will return `tk_null`.

To ensure portability, it is best to avoid using the DynUnion interface and not to rely on the ORB to behave as omniORB2 does under these ambiguous conditions.

# Duplicate DynAny References

Like any CORBA object and psuedo object references, a DynAny reference can be duplicated using the `_duplicate()` operations. When an application has obtained multiple DynAny references to the same DynAny object, it should be noted that a change made to the object by invoking on one reference is also visible through the other references. In particular, if a call through one reference has caused the current component pointer to be changed, subsequent calls through other references will operate on the new current component pointer.

# Other Operations

The following is a short summary of the other operations in the DynAny interface which have not been covered in previous sections:

`assign()`
  initialises a DynAny object with another DynAny object. The two objects must have the same typecode.

`from_any()`
  initialises a DynAny object from the value in an any. The typecode in the two objects must be the same.

`copy()`
  creates a new DynAny object whose value is a deep copy of the current object.

`type()`
  returns the typecode associated with the DynAny object.

Next: The Dynamic Invocation Up: No Title Previous: Type Any and