Type conversions
As described in the section on Types and classes, all values that are manipulated in NetRexx have an associated type. On occasion, a value involved in some operation may have a different type than is needed, and in this case conversion of a value from one type to another is necessary.
NetRexx considerably simplifies the task of programming, without losing robustness, by making many such conversions automatic. It will automatically convert values providing that there is no loss of information caused by the automatic conversion (or if there is, an exception would be raised).
Conversions can also be made explicit by concatenating a type to a value and in this case less robust conversions (sometimes known as casts) may be effected. See below for details of the permitted automatic and explicit conversions.
Almost all conversions carry some risk of failure, or have a performance cost, and so it is expected that implementations will provide options to either report costly conversions or require that programmers make all conversions explicit.[1] Such options might be recommended for certain critical programming tasks, but are not necessary for general programming.
Permitted automatic conversions
In general, the semantics of a type is unknown, and so conversion (from a source type to a target type) is only possible in the following cases:
- The target type and the source type are identical (the trivial case).
- The target type is a superclass of the source type, or is an interface class implemented by the source type. This is called type simplification, and in this case the value is not altered, no information is lost, and an explicit conversion may be used later to revert the value to its original type.
- The source type has a dimension, and the target type is Object.
- The source type is null and the target type is not primitive.
- The target and source types have known semantics (that is, they are 'well-known' to the implementation) and the conversion can be effected without loss of information (other than knowledge of the original type). These are called well-known conversions.
Necessarily, the well-known conversions are implementation-dependent, in that they depend on the standard classes for the implementation and on the primitive types supported (if any). Equally, it is this automatic conversion between strings and the primitive types of an implementation that offer the greatest simplifications of NetRexx programming.
For example, if the implementation supported an int binary type (perhaps a 32-bit integer) then this can safely be converted to a NetRexx string (of type Rexx). Hence a value of type int can be added to a number which is a NetRexx string (resulting in a NetRexx string) without concern over the difference in the types of the two terms used in the operation.
Conversely, converting a long integer to a shorter one without checking for truncation of significant digits could cause a loss of information and would not be permitted.
In the reference implementation, the semantics of each of the following types is known to the language processor (the first four are all
string types, and the remainder are known as
binary numbers):
- netrexx.lang.Rexx -- the NetRexx string class
- java.lang.String -- the Java string class
- char -- the Java primitive which represents a single character
- char[] -- an array of chars
- boolean -- a single-bit primitive
- byte, short, int, long, -- signed integer primitives (8, 16, 32, or 64 bits)
- float, double -- floating-point primitives (32 or 64 bits)
Under the rules described above, the following well-known conversions are permitted:
- Rexx to binary number, char[], String, or char
- String to binary number, char[], Rexx, or char
- char to binary number, char[], String, or Rexx
- char[] to binary number, Rexx, String, or char
- binary number to Rexx, String, char[], or char
- binary number to binary number (if no loss of information can take place -- no sign, high order digits, decimal part, or exponent information would be lost)
Notes:
- Some of the conversions can cause a run-time error (exception), as when a string represents a number that is too large for an int and a conversion to int is attempted, or when a string that does not contain exactly one character is converted to a char.
- The boolean primitive is treated as a binary number that may only take the values 0 or 1. A boolean may therefore be converted to any binary number type, as well as any of the string (or char) types, as the character '0' or '1'. Similarly, any binary number or string can be converted to boolean (and must have a value of 0 or 1 for the conversion to succeed).
- The char type is a single-character string (it is not a number that represents the encoding of the character).
Permitted explicit conversions
Explicit conversions are permitted for all permitted automatic conversions and, in addition, when:
- The target type is a subclass of the source type, or implements the source type. This conversion will fail if the value being converted was not originally of the target type (or a subclass of the target type).
- Both the source and target types are primitive and (depending on the implementation) the conversion may fail or truncate information.
- The target type is Rexx or a well-known string type (all values have an explicit string representation).
Costs of conversions
All conversions are considered to have a cost, and, for permitted automatic conversions, these costs are used to select a method for execution when several possibilities arise, using the algorithm described in Methods and Constructors.
For permitted automatic conversions, the cost of a conversion from a source type to a target type will range from zero through some arbitrary positive value, constrained by the following rules:
- The cost is zero only if the source and target types are the same, or if the source type is null and the target type is not primitive.
- Conversions from a given primitive source type to different primitive target types should have different costs. For example, conversion of an 8-bit number to a 64-bit number might cost more than conversion of a 8-bit number to a 32-bit number.
- Conversions that may require the creation of a new object cost more than those that can never require the creation of a new object.
- Conversions that may fail (raise an exception) cost more than those that may require the creation of an object but can never fail.
Within these constraints, exact costs are arbitrary, and (because they mostly involve implementation-dependent primitive types) are necessarily implementation-dependent. The intent is that the 'best performance' method be selected when there is a possibility of more than one.