Managed COBOL distinguishes between:
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. During boxing, the system copies the value into the object heap and returns a reference to it.
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:
See the ValueTypes sample, available from Start > All Programs > Micro Focus Visual COBOL > Samples and under COBOL for .NET.
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:
imperative-clause TYPE OF type-name
*>Value Types *>condition-value *>binary-char (unsigned) *>character *>binary-short, binary-long, binary-double (unsigned) *>float-short, float-long *>decimal *>DateTime (a framework type) *>Reference types *>object *>string *>Initializing declare correct as condition-value = true *> Can also infer variable type if the value has a well-defined type declare incorrect = false *> automatically a condition-value declare b as byte = h"2a" *> hex declare o as byte = o"52" *> octal declare b2 as byte = b"101010" *> binary declare person as object = null declare nam as string = "Dwight" declare grade as character = "B" declare now as type DateTime = type DateTime::Now *> No support for date/time literals declare amount as decimal = 35.99 declare gpa as float-short = 2.9 declare pi as float-long = 3.14159265 declare lTotal as binary-double = 123456 declare sTotal as binary-short = 123 declare usTotal as binary-short unsigned = 123 declare uiTotal as binary-long = 123 declare ulTotal as binary-long unsigned = 123 *>Type Information declare x as binary-long display x::GetType *> Prints System.Int32 display type of binary-long *> Prints System.Int32 display x::GetType::Name *> Prints Int32 *>Type Conversion declare f as float-short = 3.5 *> automatic conversion declare i = f as binary-long *> set to 3 (truncates decimal) end program. program-id Legacy. *> COBOL types not supported directly by other languages. *> Visual COBOL supports these types on all platforms. *> Only a few examples here 01 displayNumber pic 9(9).99. 01 computeNumber pic 9(9)V99. 01 alphaNumberic pic a(23). 01 binaryStorage pic x(12). *> Also groups and redefines - a few examples 01 arecord. 03 aSubRecord pic x(10). 03 aUnion pic 9(10) redefines aSubrecord. end program.
A type conversion allows an expression of some type to be converted to a different type. There are two kinds of type conversion, explicit and implicit. In order to perform an explicit conversion, it is necessary to use the AS keyword, specifying the required target type. An example of this type of conversion is:
Declare myAnimal as type Animal Declare myWarthog as type Warthog … Set myWarthog to myAnimal as type Warthog *> Convert type Animal to type Warthog
The explicit conversion is necessary because not all objects of type Animal are of type Warthog.
An example of an implicit conversion is:
Set myAnimal to myWarthog
Because type Warthog derives from type Animal, the conversion is always legitimate and can be done implicitly. Similarly, using implicit conversion, myWarthog can be passed as a parameter to any method that expects an argument of type Animal.
COBOL allows the following kinds of implicit conversion:
The main contexts in which implicit conversions occur are:
An implicit conversion from type S to type T is allowed in the following cases:
Some examples of implicit reference conversions:
01 appDomain type System.AppDomain. 01 obj object. 01 myList type List[string]. 01 myEnumerable type IEnumerable[string]. 01 objArray object occurs 10. 01 strArray string occurs 10. set obj to appDomain *> type System.AppDomain derives from System.Object set appDomain to obj *> produces compile time error set myEnumerable to myList *> List[string] implements IEnumerable[string] set objArray to strArray *> source element type derives from target element type
In .NET COBOL, any value type can be converted to a reference type, either of type System.Object or of type System.ValueType. An enum type can also be converted to type System.Enum.
In JVM COBOL, the primitive types may be converted to boxed types as follows:A user defined implicit conversion exists from type S to type T if there exists an implicit user defined type conversion operator (see below) from type S1 to type T1 such that:
An anonymous method with signature S can be converted to any delegate type with the same signature and return type. Also, an anonymous method with no parameters can be converted to any delegate type with the same return type.
A method group with method name method-name can be converted to a delegate type with signature S and return type R if there exists a method within that method group (i.e. a method with the specified name) with the same signature and return type.
Explicit conversions are specified using the AS keyword. They can be used anywhere an expression of the target type is permitted.
COBOL allows the following kinds of explicit conversion:
Any enum type may be explicitly converted to any numeric type.
Any numeric type may be explicitly converted to any enum type.
An explicit conversion from type S to type T is allowed in the following cases:
If an explicit reference conversion 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.
Some examples of explicit reference conversions:01 appDomain type System.AppDomain. 01 obj object. 01 myList type List[string]. 01 myEnumerable type IEnumerable[string]. 01 objArray object occurs 10. 01 strArray string occurs 10. *> Following allowed as type System.AppDomain derives from object set appDomain to obj as type System.AppDomain *> Following allowed as list[string] implements IEnumerable[string] set myList to myEnumerable as type List[string] *> Following allowed as there exists an explicit reference conversion *> from object (the element type of objArray) to string (element type of strArray) set strArray to objArray as string occurs any *> explicit conversions can be used anywhere… display obj as type System.AppDomain set obj to type of object *> sets obj to a System.Type object *> The following will throw an exception set appDomain to obj as type System.AppDomainAn 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.
In .NET COBOL, items of type System.Object or of type System.ValueType can be explicit converted to a value type. Items of type System.Enum can be converted to enum types.
01 obj object. 01 dt type System.DateTime. Set obj to dt *> this is an implicit conversion using boxing Set dt to obj as type System.DateTime *> explicit unboxing conversionIn JVM COBOL, following types may be converted to primitive types:
A user defined explicit conversion exists from type S to type T if there exists an explicit user defined type conversion operator (see below) from type S1 to type T1 such that:
A conversion operator converts a data item from one data type into another, such as from a type that you have defined into an 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 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 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.
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