Arithmetic Operators¶
Quxlang's arithmetic operators are +, -, *, /, and %. Their meaning
comes from the operand type's operator contract; the primitive numeric types
provide the built-in forms listed here.
Primitive arithmetic¶
Integers and BYTE support all five binary operators with operands and result
of the same concrete type:
VAR left I32 := 17;
VAR right I32 := 5;
ASSERT(left + right == 22);
ASSERT(left - right == 12);
ASSERT(left * right == 85);
ASSERT(left / right == 3);
ASSERT(left % right == 2);
Floating-point types support +, -, *, and /; % has no built-in
floating-point overload.
Primitive runtime arithmetic does not apply the usual C integer promotions.
The built-in overload takes two values of the same concrete integer,
BYTE, or floating-point type and returns that type. Convert an operand
explicitly when widths or signedness differ.
See Conversions for CHECKED, PARTIAL, and other
conversion modes.
Numeric literals¶
Two untyped numeric literals are evaluated as arbitrary-precision compile-time literals. The result remains a literal until a construction or conversion selects a concrete type:
A literal used with a concrete operand is adapted through ordinary overload resolution. It must fit the target type when that conversion requires an exact value.
Unary signs¶
Prefix + preserves a numeric value and prefix - negates it where the type
provides the corresponding unary operation. Parenthesize a negative value when
it participates in a conversion or a lower-precedence binary expression:
Pointer and address arithmetic¶
Array pointers (=>>T) support element-based arithmetic:
| Expression | Result |
|---|---|
pointer + offset |
Array pointer advanced by offset elements |
pointer - offset |
Array pointer retreated by offset elements |
left - right |
Signed pointer-sized element distance |
The offset may be the target's signed or unsigned pointer-sized integer. The
pointers must refer into the same valid array object. Instance
pointers (->T) do not provide pointer arithmetic.
ADDRESS provides byte-oriented arithmetic instead. address + size and
address - size produce another ADDRESS; subtracting two ADDRESS values
produces an unsigned pointer-sized byte distance.
See Pointers for validity rules that arithmetic does not override.
User-defined arithmetic¶
For left operator right, Quxlang first looks for an applicable
left_type::.OPERATOR<operator> and then for the reflected
right_type::.OPERATOR<operator>RHS. Normal overload resolution and argument
adaptation select the callable declaration.
::distance STRUCT
{
.meters VAR I32;
.OPERATOR+ FUNCTION(@OTHER CONST& distance): distance
{
RETURN distance(@meters .meters + OTHER.meters);
}
}
An overload changes the operation for its types but not the parser's precedence or associativity. See User-Defined Operators.
Precedence¶
Quxlang's current precedence differs from C-family languages: * binds more
tightly than + and -, while + and - bind more tightly than / and %.
Operator Precedence specifies the grouping of mixed
arithmetic forms.
Integer range contracts¶
Ordinary integer addition, subtraction, and multiplication wrap to the declared bit width. Explicit suffixes select a different contract:
| Operation | Checked | Assumed in range |
|---|---|---|
| Add | +? |
+! |
| Subtract | -? |
-! |
| Multiply | *? |
*! |
| Divide | /? |
/! |
The checked forms throw ARITHMETIC_OVERFLOW for an unrepresentable result;
checked division also rejects a zero divisor. Assumed-in-range forms require a
valid result and nonzero divisor. With CHECK_OVERFLOW enabled, a violation
panics; with it disabled, a violation is undefined behavior. These forms are
for concrete integer types and BYTE.
VAR value U8 := 255;
TRY
{
value +=? 1;
}
CATCH overflow CONST& ARITHMETIC_OVERFLOW
{
TEST_ASSERT(value == 255);
}
VAR small I32 := 12;
VAR doubled I32 := small *! 2;
TEST_ASSERT(doubled == 24);
Mutating forms put = before the suffix: +=?, -=?, *=?, /=?,
and +=!, -=!, *=!, /=!.
A failing checked operation leaves its destination unchanged. The suffixed
operators have the same precedence as their ordinary forms. There are no
%? or %! operators. JVM support for checked arithmetic exceptions is
currently incomplete.
See Compilation Policies and Bitwise Operators for checked shifts and rotations.
Address remainder¶
address % divisor accepts an unsigned pointer-sized divisor and returns an
unsigned pointer-sized remainder. This can test external-address alignment:
The divisor must be nonzero. Address remainder requires runtime execution; constant evaluation rejects it.