When an expression mixes SIGNED and UNSIGNED integer values, ECL determines a common base type for the sub-expression. That common type is always SIGNED. This means that an explicit cast to an UNSIGNED type can be silently undone when the other operand in the same expression is SIGNED.
Bare integer literals (such as 100) are treated as SIGNED. Therefore an expression of the form (UNSIGNED8)value % 100 is evaluated as (SIGNED) % (SIGNED), and the result is SIGNED—even though one operand was explicitly cast to UNSIGNED8.
To guarantee unsigned arithmetic, every operand in the sub-expression must be explicitly cast to an UNSIGNED type.
ExampleRec := RECORD
INTEGER8 signed_hash64_value;
UNSIGNED8 unsigned_hash64_value;
INTEGER2 implicit_casting_result;
INTEGER2 explicit_casting_result;
END;
ExampleRec MakeExampleRec(UNSIGNED1 c) := TRANSFORM
h := HASH64(c);
SELF.signed_hash64_value := h;
SELF.unsigned_hash64_value := (UNSIGNED8)h;
// bare 100 is SIGNED, so (UNSIGNED8)h % 100 resolves as (SIGNED) % (SIGNED)
SELF.implicit_casting_result := (UNSIGNED8)h % 100;
// both operands explicitly UNSIGNED: result stays UNSIGNED
SELF.explicit_casting_result := (UNSIGNED8)h % (UNSIGNED1)100;
END;
ds := DATASET(10, MakeExampleRec(COUNTER));
OUTPUT(ds);
//*********************************************************************************************
/*
Results:
signed_hash64_value unsigned_hash64_value implicit_casting_result explicit_casting_result
----------------------------------------------------------------------------------------------
-2056600594528442646 16390143479181108970 -46 70
2171580671610491919 2171580671610491919 19 19
6399761937749426484 6399761937749426484 84 84
-7818800869821190567 10627943203888361049 -67 49
-3590619603682256002 14856124470027295614 -2 14
637561662456678563 637561662456678563 63 63
4865742928595613128 4865742928595613128 28 28
9093924194734547693 9093924194734547693 93 93
-5124638612836069358 13322105460873482258 -58 58
-896457346697134793 17550286727012416823 -93 23
*/The implicit_casting_result column produces negative values for rows where HASH64 returned a negative signed integer, because the explicit UNSIGNED8 cast is overridden by implicit promotion. The explicit_casting_result column always produces a non-negative value because both operands are unsigned.