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
For example, in .NET COBOL:
*>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 or AS IF phrase, 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 an argument to any method that has a by value parameter of type Animal.
COBOL allows the following kinds of implicit conversion:
The main contexts in which implicit conversions occur are:
The numeric literal 0 can be converted to any enum type.
An implicit conversion from type S to type T is allowed in the following cases:
Note that in .NET COBOL:
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 [ IF ] phrase. They can be used anywhere that 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 (also known as a cast) is allowed in the following cases:
If the cast fails, an exception is thrown (InvalidCastException for .NET or ClassCastException for JVM). To avoid this, you can: test for a valid cast first using INSTANCE OF; wrap the cast in an exception block (see the TRY Statement for more information); or use the AS IF phrase, which in the case of an invalid cast sets the target object to null and does not throw an exception (see cast expressions for more information).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.AppDomain *> *> this statement does not fail, but sets myString to null *> set myString to myObject as if stringAn 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
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.
Creating implicit conversions
For example, the type Timer, which contains hours and minutes, is converted into minutes as binary-long using the following conversion operator:
operator-id Implicit (a as type Timer) returning b as binary-long. set b to a::Hour * 60 + a::Minutes end operator.
This operator can then be used in statements such as:
set myMins to timer3
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:
operator-id Implicit (a as binary-long) returning b as type Timer. set b to new Timer declare hour as binary-long = a / 60 set b::Hour to hour set b::Minutes to a - 60 * hour end operator.
This operator can then be used in statements such as:
set timer4 to myMins
Implicit conversions can occur in all sorts of places, such as assignments and member invocations.
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.
Creating explicit conversions
operator-id Explicit (a as String) returning b as type Timer. 01 strH String. 01 strM String. 01 colonPos binary-long value 0. 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::Hour to type Int32::Parse(strH) set b::Minutes to type Int32::Parse(strM) catch display "Invalid time format" end-try end operator.
Explicit conversions occur only in statements that explicitly state the type to convert to. For example, where the conversion operator is defined as explicit, only the second statement below works:
set timer4 to myString *> fails to compile as no implicit conversion exists set timer4 to myString as type Timer *> succeeds
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.