Previous Topic Next topic Print topic


Types and Type Conversion

Value Types, Reference Types and Boxing

Managed COBOL distinguishes between:

  • Value types (such as binary-long and System.DateTime in .NET). Value type data items contain the actual data. For example, a COBOL binary-long data item contains a 32 bit integer.
  • Reference types, which are allocated on the object heap. Reference type data items hold a reference into the object heap. Reference types are under the management of the garbage collector.

All value types can be turned into reference types by a process known as boxing. For example, you can set an object reference to a value type, such as a binary-long.

Boxing happens automatically when needed, for example when a value type is passed as a parameter to a method that expects an object as a parameter.

You can box explicitly by assigning a value type to a generic object (such as System.Object in .NET COBOL or java.lang.Object in JVM COBOL).

You can unbox value types to restore the original value type.

When you specify TYPE classname in the data item definition:

  • If classname represents a reference type, you get a reference type object.
  • If classname represents a value type, you get a value type object.

During boxing, the system copies the value into the object heap and returns a reference to it. When the reference is no longer active (because nothing in the program is holding on to it), the space in the object heap will eventually be regained by the garbage collector.

See the ValueTypes sample, available from Start > All Programs > Micro Focus Studio Enterprise Edition > Samples and under COBOL for .NET.

Type Information

Every class has an associated root object, which can be used to get information about the class such as its fields and methods. To obtain type information, you use the following:

  • In NET COBOL, GetType() - to obtain the System.Type object for an object reference
  • In JVM COBOL, getClass() - to obtain the java.lang.Object to obtain the class of an object reference
  • TYPE OF - to obtain the System.Type object for a class, interface, delegate or enumeration
    imperative-clause TYPE OF object

For example, in .NET COBOL:

*> Type information
01 x binary-long.
display x::GetType            *> Prints System.Int32
display type of binary-long   *> Prints System.Int32
display x::GetType::Name      *> Prints Int32

For example, in JVM COBOL:

*> Type information
01 x binary-long.
display x::getClass           *> Prints System.Int32
display type of binary-long   *> Prints System.Int32
display x::getClass::Name     *> Prints Int32

Type Conversion Operators

A conversion operator converts a data item from one data type into another, such as from a type that you have defined into a integer. Conversion operators can be overloaded, so that the appropriate conversion operator is used according to the parameter types in the calling code.

For example, the type Timer, which contains hours and minutes, is converted into minutes as binary-long using the following conversion operator:

       set myMins to timer3 ...
       operator-id Implicit.
       procedure division using value a as type Timer 
                          returning b as binary-long.
            set b to a::pHour * 60 + a::pMins
       end operator.      

Similarly, you can convert from a binary-long data item (representing a number of minutes) to the type Timer, which is expressed in hours and minutes, using the following conversion operator:

       set timer4 to myMins ...
       operator-id Implicit.
       procedure division using value a as binary-long 
                          returning b as type Timer.
             set b to new Timer
             if a >= 60
                 set b::pHour to 1
                 set b::pMins to a - 60 
             else
                 set b::pMins to a
             end-if
       end operator.

You can define explicit conversions, in addition to implicit conversions. They differ as follows:

Explicit conversions
Explicit conversions occur only in statements that explicitly state the type to convert from. For example, where the conversion operator is defined as explicit, only the second statement below works:
       set timer4 to myString                *> fails 
       set timer4 to myString as type Timer  *> succeeds
       operator-id Explicit.
       01 strH type String.
       01 strM type String.
       01 colonPos  binary-long value 0.
 
       procedure division using value a as String returning b as Type Timer. 
           set b to new Timer()
           set colonPos to a::IndexOf(":")
           try
               set strH to a::Substring(0 colonPos)
               set strM to a::Substring(colonPos + 1 2)
               set b::pHour to type Int32::Parse(strH)
               set b::pMins to type Int32::Parse(strM)
           catch
               display "Invalid time format"
           end-try
       end operator.

You use explicit conversions (as opposed to implicit ones) where the conversion has the potential to lose information or throw an exception. In the above example, the string might contain text or be invalid somehow. In this case, a try-catch block is required to handle the failure.

Implicit conversions
Implicit conversions can occur in all sorts of places, such as assignments and member invocations and an explicit conversion. See the earlier examples.

You can invoke an implicit conversion implicitly or explicitly. For example, the following statements both invoke the implicit conversion:

       set myMins to timer3 
       set myMins to timer3 as binary-long

You use implicit conversions where the conversion is reliable, where it will not lose information and will not throw an exception.

Casting Object References Using AS

You can cast an object reference to an instance of another type using AS. The Compiler can then check whether the operation is type safe or not.

In the following example, we know that obj-object points to a System.AppDomain reference so we know we can cast up the class hierarchy from System.Object to System.AppDomain.

   
    *> set obj-app-domain to obj-object             *> fails if uncommented
     set obj-app-domain to obj-object as type System.AppDomain *> succeeds

Casts can be inline, so you can do the following:

display obj-object as type System.AppDomain::FriendlyName

A cast is only legal if the target type (the type being cast to) derives directly from the source type, or vice versa. In the following statement a System.Type reference (obj-type) can never point to a System.AppDomain instance because the classes are unrelated in the hierarchy.

   
       *>set obj-app-domain to obj-type as type System.AppDomain *> fails if uncommented

If the cast fails, a System.InvalidCastException is thrown by the CLR. To avoid this, either test for a valid cast first using INSTANCE OF or wrap the cast in an exception block (see exception handling example for more information).

An exception is thrown in the following as we are claiming obj-object references a System.AppDomain instance where in fact it's referencing a System.Type instance.

   *> these statements fail if uncommented  
       *> set obj-object to obj-type                 
       *> set obj-app-domain to obj-object as type System.AppDomain  
 
Previous Topic Next topic Print topic