Assignment compatibility in EGL

Assignment compatibility rules apply in either of the following situations:
A different set of rules is in effect in the following cases:

For more information about those cases, including assigning a reference variable to a value variable (and the other way around), see Reference compatibility in EGL.

In the following tables, the types in the leftmost column represent the left hand side (the target) of the assignment statement, and all other columns represent the right hand side (source). The letter Y indicates compatible types. A blank means the types are not compatible. A number refers to notes that follow the third table, detailing the circumstances under which the types are compatible.

The first table deals with text types as the source of the assignment.

Table 1. Assignment compatibility: Text types
Target Source
  CHAR MBCHAR STRING, UNICODE DBCHAR
CHAR Y Y Y  
MBCHAR Y Y Y  
STRING, UNICODE Y Y Y Y
DBCHAR     Y Y
BIN 1 1 1  
INT, BIGINT, SMALLINT 1 1 1  
DECIMAL 1 1 1  
NUM 1 1 1  
NUMBER 1 1 1  
FLOAT, SMALLFLOAT 1 1 1  
MONEY 1 1 1  
NUMC 1 1 1  
PACF 1 1 1  
DATE 2 2 2  
INTERVAL (months) 2 2 2  
INTERVAL (seconds) 2 2 2  
TIME 2 2 2  
TIMESTAMP 2 2 2  
HEX Y   Y  
BOOLEAN        

The second table deals with numeric types as the source of the assignment.

Table 2. Assignment compatibility: Numeric types
Target Source
  BIN

INT,
BIGINT, SMALL-
INT

DECI-
MAL

NUM

NUM-
BER

FLOAT,
SMALL-
FLOAT

MONEY NUMC PACF
CHAR Y Y Y Y Y Y 3 Y Y
MBCHAR Y Y Y Y Y Y 3 Y Y
STRING 4 4 4 4 4 4 3, 4 4 4
UNICODE Y Y Y Y Y Y 3 Y Y
DBCHAR Y Y Y Y Y Y Y Y Y
BIN Y Y Y Y Y Y Y Y Y
INT, BIGINT, SMALLINT Y Y Y Y Y Y Y Y Y
DECIMAL Y Y Y Y Y Y Y Y Y
NUM Y Y Y Y Y Y Y Y Y
NUMBER Y Y Y Y Y Y Y Y Y

FLOAT,
SMALL-
FLOAT

Y Y Y Y Y Y Y Y Y
MONEY Y Y Y Y Y Y Y Y Y
NUMC Y Y Y Y Y Y Y Y Y
PACF Y Y Y Y Y Y Y Y Y
DATE 5 5 5 5 5 5 5 5 5
INTERVAL (months) 6 6 6 6 6 6 6 6 6
INTERVAL (seconds) 6 6 6 6 6 6 6 6 6
TIME                  
TIMESTAMP                  
HEX           7      
BOOLEAN 8 8 8 8 8 8 8 8 8

The third table deals with date/time, hex, and Boolean types as the source of the assignment.

Table 3. Assignment compatibility: Other types
Target Source
  DATE INTERVAL (months) INTERVAL (seconds) TIME

TIME-
STAMP

HEX BOOLEAN
CHAR 9 9 9 9 9 Y  
MBCHAR 9 9 9 9 9    
STRING, UNICODE 9 9 9 9 9 Y  
DBCHAR              
BIN 10 Y Y       11
INT, BIGINT, SMALLINT 10 Y Y       11
DECIMAL 10 12 12       11
NUM 10 12 12       11
NUMBER 10 12 12       11
FLOAT, SMALLFLOAT 10         Y 11
MONEY 10 12 12       11
NUMC 10 12 12       11
PACF 10 12 12       11
DATE Y       Y    
INTERVAL (months)   Y          
INTERVAL (seconds)     Y        
TIME       Y Y    
TIMESTAMP Y     Y Y    
HEX           Y  
BOOLEAN             Y
Note:
  1. The text must depict a literal of the receiving data type. It can include the exponent notation, a leading sign, decimal separator other than period (depending on the language settings) and the currency symbol (when being assigned to a money type). It can have any number of leading or trailing spaces, but none in between.
  2. See Converting text to date/time types.
  3. A locale-dependent currency symbol is automatically added to the beginning of the target on assignment. In a comparison, the first character of a text value is ignored if it is a currency symbol. The strings "$10.20" and "10.20" are both equal to a MONEY variable with the value 10.20.
  4. EGL uses strLib.formatNumber() with no pattern argument whenever it converts a numeric type to a STRING. This includes assignments and string concatenations. See formatNumber().
  5. If the numeric type contains decimals, EGL truncates them; the number is assumed to be the number of days since December 31, 1899. Thus the following code prints "03/21/2006" on the console:
      Function main()
        testBin BIN(9,3) = 38796.999;
        testDate DATE;
        
        StrLib.defaultDateFormat = "MM/dd/yyyy";
        testDate = testBin;
        writeStdout (testDate);
      end
  6. This is valid only if the numeric value has no decimal digits. The number is interpreted according to the format of the interval. Consider the following example:
    myInterval INTERVAL("yyMM") = 1208;
    Here EGL interprets the number 1208 as twelve years and eight months. The following rules apply:
    • If the number has more digits than the interval can hold, disregarding leading zeros, the extra digits on the right are ignored.
    • If the number has fewer digits than the interval can hold, leading zeros are added.
    • The interval's sign is set to the sign of the number.
    • If the number specifies an out-of-range value for a field of the interval, EGL carries the excess to the next field. Consider this example:
      myInterval INTERVAL("yyMM") = 8216;
      EGL assigns the interval 83 years and 4 months. There are only 12 months in a year, so the "16" is treated as four months and another year is added to the original 82.
    • If a value must be carried from the leftmost field of the interval, it is not an error. The extra digits are simply discarded. Here's another example:
      myInterval INTERVAL("yyMM") = 9925;
      EGL assigns the interval 1 year and 1 month. 25 months = 2 years and 1 month, so months = 01. The years value is 99, plus 2 carried from the months = 101, which is truncated to 01.
  7. To assign a value other than a FLOAT, SMALLFLOAT, or another HEX (including a literal), cast the value using the as operator.
  8. If the numeric variable has any non-zero value, positive or negative, EGL assigns the value TRUE to the BOOLEAN variable; only a numeric 0 results in a FALSE BOOLEAN value.
  9. See Converting date/time types to text.
  10. When you assign a DATE to a numeric type, the value is the number of days since December 31, 1899.
  11. If the BOOLEAN variable is TRUE, EGL assigns the value 1 to the numeric type; if FALSE, it assigns 0.
  12. Valid only if the target variable has no decimal places.

Rounding and truncation between numeric types

A value of any of the numeric types (including NUMC and PACF) can be assigned to a variable of any numeric type and size, and EGL does the conversions necessary to retain the value in the target format.

Non-significant zeros are added or truncated as needed. (Initial zeros in the integer part of a value are non-significant, as are trailing digits in the fraction part of a value.)

If you use V6 exception mode and set vgVar.handleOverflow accordingly, you can use the sysVar.overflowIndicator system variable to test whether an assignment or arithmetic calculation resulted in an overflow. For more information, see handleOverflow. If you do not use V6 exception mode, or do not handle overflows, an overflow will cause EGL to throw a RuntimeException.

Given a runtime value of 108.314 for the source, the following actions result when you copy one DECIMAL variable to another:
  • If the target variable allows seven digits with one decimal place, the target variable receives the value 000108.3, and an overflow is not detected. (A loss of precision in a fractional value is not considered an overflow.)
  • If the target variable allows four digits with two decimal places, an overflow is detected.

In an assignment statement, extra decimal digits are truncated when the truncateExtraDecimals build descriptor option is YES (the default; for more information see the EGL Generation Guide), unless the source is a FLOAT or SMALLFLOAT and the target has a fixed number of decimals. Extra decimal digits are rounded when truncateExtraDecimlas is set to NO or the source is a FLOAT or SMALLFLOAT and the target has a fixed number of decimals.

In version 6 and previous versions of EGL, the truncateExtraDecimals option did not exist, so extra decimals were always truncated unless the source was a FLOAT or SMALLFLOAT and the target had a fixed number of decimals. An additional rule prevented truncation if the source of the assignment was one of the MathLib functions. If you need to maintain this V6 style rounding, use the MathLib.assign() function (see assign()).

Padding and truncation with character types

If the target is of a non-STRING character type (including DBCHAR and HEX) and has more space than is required to store a source value, EGL pads data on the right, in the following ways:
  • Single-byte blanks pad a target of type CHAR or MBCHAR.
  • Double-byte blanks pad a target of type DBCHAR.
  • Unicode double-byte blanks pad a target of type UNICODE.
  • Binary zeros pad a target of type HEX, which means (for example) that a source value "0A" is stored in a two-byte target as "0A00" rather than as "000A".

EGL truncates values on the right if the target of a character type has insufficient space to store the source value. No error is signaled.

If the target is a limited-length string, the following rules apply:
  • If more characters are in the source than are valid in the target, EGL runtime truncates the copied content to fit the available length.
  • If fewer characters are in the source than are valid in the target, EGL runtime pads the copied content with blanks, to the length of the target string. However, any trailing blanks in a limited-length string are ignored in a comparison.
A special case can occur in the following situation:
  • The runtime platform supports the EBCDIC character set
  • The assignment statement copies a literal of type MBCHAR or a variable of type MBCHAR to a shorter variable of type MBCHAR
  • A byte-by-byte truncation would remove a final shift-in character or split a double-byte character

In this situation, EGL truncates characters as needed to ensure that the target variable contains a valid string of type MBCHAR, then adds (if necessary) terminating single-byte blanks.

Assignment to or from nullable types

Nullable variables are assignment compatible with variables that are not nullable, provided their base types are assignment compatible. If a variable that is not nullable is assigned to a variable that is nullable, the assignment follows the rules explained earlier in this topic. The target variable is never set to null in this case because the source variable cannot be null. If a nullable variable is assigned to a variable that is not nullable, the behavior depends on the type of the data and whether the source is currently null. The following rules explain that behavior:
  • If the source is currently null and the target is a character variable, the target variable is set to blank.
  • If the source is currently null and the target variable is numeric, the target variable is set to 0.
  • If the source is not null, the assignment follows the normal assignment rules.

Nullable variables are reference compatible only with other nullable variables that have the exact same base type. The assignment follows the rules described in Reference compatibility in EGL.

Assignment between timestamps

If you assign one TIMESTAMP variable to another TIMESTAMP variable, the following rules apply:
  • If the mask of the source variable is missing relatively high-level entries that are required by the target variable, those target entries are assigned in accordance with the clock on the machine at the time of the assignment, as the following examples show:
    •   sourceTimeStamp timestamp ("MMdd");
         targetTimeStamp timestamp ("yyyyMMdd");
        
         sourceTimeStamp = "1201";
      
        // if this code runs in 2004, the next statement
        // assigns 20041201 to targetTimeStamp
         targetTimeStamp = sourceTimeStamp; 
    •   sourceTimeStamp02 timestamp ("ssff");
        targetTimeStamp02 timestamp ("mmssff");
        
         sourceTimeStamp02 = "3201";
      
        // the next assignment includes the minute
        // that is current when the assignment statement runs
        targetTimeStamp02 = sourceTimeStamp02;
    • If the mask of the source variable is missing relatively low-level entries that are required by the target variable, those target entries are assigned the lowest valid values, as the following examples show:
      • sourceTimeStamp timestamp ("yyyyMM");
        targetTimeStamp timestamp ("yyyyMMdd");
        
        sourceTimeStamp = "200412";
        
        // regardless of the day, the next statement
        // assigns 20041201 to targetTimeStamp
        targetTimeStamp = sourceTimeStamp; 
      • sourceTimeStamp02 timestamp ("hh");
        targetTimeStamp02 timestamp ("hhmm");
        
        sourceTimeStamp02 = "11";
        
        // regardless of the minute, the next statement
        // assigns 1100 to targetTimeStamp02
        targetTimeStamp02 = sourceTimeStamp02;

Assignment to or from fields in structured records

You can assign a substructure field to a non-substructure field or the reverse, and you can assign values between two substructure fields. Assume, for example, that variables named myNum and myRecord are based on the following parts:

  DataItem Num12
    NUM(12)
  end

  Record ExampleRecord type basicRecord
    10 topMost CHAR(4);
      20 next01 HEX(4);
      20 next02 HEX(4);
  end

The assignment of a value of type HEX to a variable of type NUM is not valid outside of the mathematical system variables; but an assignment of the form myNum = topMost is valid because topMost is of type CHAR. In general terms, the primitive types of the fields in the assignment statement guide the assignment, and the primitive types of subordinate fields are not taken into account.

By default, the primitive type of a substructure field is CHAR. If you assign data to or from a substructure field and do not specify a different primitive type at declaration time, the rules described earlier for fields of type CHAR are in effect during the assignment.

Assignment of a structured record

An assignment of one structured record variable to another is equivalent to assigning one substructure field of type CHAR to another. A mismatch in length adds single-byte blanks to the right of the received value or removes single-byte characters from the right of the received value. The assignment does not consider the primitive types of subordinate structure fields.

The following exceptions apply:
  • The content of a record can be assigned to a record variable or to a variable of type CHAR, HEX, STRING, or MBCHAR, but not to a variable of any other type
  • A record can receive data from any of the following sources:
    • another record
    • a string literal (but not a numeric literal)
    • a CHAR, HEX, STRING, or MBCHAR variable (no other type is permitted)

Finally, if you assign a structured SQL record variable to or from a structured record variable of a different type, you must ensure that the non-SQL record has space for the four-byte area that precedes each structure field (for more information, see Structured records).

Assignment between records

Non-structured record variables are assignment compatible only with other non-structured record variables of exactly the same type.

Achieving consistent results across environments

Due to truncation of intermediate results, COBOL programs might have different results than Java™ or Rich UI programs for the same arithmetic statements. To ensure consistent results across environments, use only one binary operator per statement. Multiple addition and subtraction operators can be safely combined if the number of decimal places defined for the result item is greater than or equal to the number of decimal places in any of the operands.

The remainder operator can produce inconsistent results if the result or any of the operands are defined with decimal places greater than zero. To get a consistent remainder with decimal places, use the following algorithm instead of the remainder operator:
quotient = dividend / divisor;
remainder = dividend - (quotient * divisor);

Compatibility

Table 4. Compatibility considerations for assignments
Platform Issue
COBOL generation EGL is unable to convert text to SMALLFLOAT or FLOAT, though it can convert in the other direction.