Zax integer operator catalog
| Field | Value |
|---|---|
| Status | Current conceptual design |
| Audience | Human developers looking up protected behavior for Zax integer operations |
| Applies To | Built-in finite F = 0 integer operations for concrete-endian exact and role-selected identities; not fixed-point arithmetic, custom overload behavior, formal grammar, or a specification |
| Implementation State | Not established by this repository |
| Owns | Protected integer operand domains, availability, result identities, policy behavior, failure, mutation, conversion/admission, count/mask/shift behavior, delta, distance, and unchecked arithmetic contracts |
| Does Not Own | Uncommitted integer evaluation and realization (integer literals and realization); integer type choice and representation (integers); fixed-point F > 0 operations (fixed-point scalars); exact forms/fixity/precedence (operator catalog); shared discovery/selection (operators); or general identity behavior (identity types) |
| Source / Provenance | Integer behavior formerly embedded in the general operator catalog, reorganized after fundamental-integer review |
How to use this catalog
Zax integers explains which integer type to choose and how its range, representation, identity, and storage behave.
This catalog answers what a protected operation does after its integer operands and result domain are known. Operands normally share one concrete-endian identity. Mixed-endian values require explicit numeric conversion before the operation; the implementation may then use CPU-native registers while preserving the selected type’s byte order.
The general operator catalog remains authoritative for:
- recognized symbolic and phrase forms;
- fixity;
- precedence and association;
- protected versus open forms; and
- source-tree formation.
Custom overloads may assign domain-specific behavior and result shapes where the form is open. The rules below apply only to protected integer signatures.
Number literals before a concrete type
Compare:
myMathematicalResult : U8 = 200 + 55
myTypedResult := (: U8 = 200) + 55
In the first declaration, 200 + 55 is calculated mathematically before the
final 255 is checked against U8. In the second, the left operand is already
U8, so the addition uses the concrete U8 overflow rules in this catalog.
Plain negation, magnitude, arithmetic, division, remainder, mathematical shifts, width-invariant binary bitwise operations, and comparison can operate on not-yet-typed number literals as described by Zax integer literals and realization. Complement is available there only when value and sign intent produce one result at every fitting width.
This catalog describes operations after an exact or role-selected integer type is known, including finite overflow, policy suffixes, optional/reporting results, mutation, finite-width bitwise behavior, shifts, and associated result types.
A typed operand can also determine the integer type for a number literal on its other side:
myValue := 0 + (: U8 = 5)
The right operand is U8, so 0 is checked as though the programmer wrote
(: U8 = 0). Ordinary concrete U8 + U8 behavior then applies. This special
relationship belongs to the built-in integer operation; the right operand still
does not contribute custom declarations.
Shared integer-operation rules
Unless a family below says otherwise:
- value operands use the same integer identity;
- each runtime operand evaluates once from left to right;
- the result retains the operand integer identity;
- no implicit widening, narrowing, signedness change, or role conversion occurs;
- an identity-preserving alias is the same operand type;
- a distinct integer role identity remains distinct even when its representation matches another role;
- compile-time execution uses the same value semantics; and
- a compile-time-known panic becomes a compiler diagnostic.
Dedicated operand roles are explicit exceptions. Shift counts use an accepted unsigned count type, and an integer’s associated bit-count type is always directly accepted.
Addition, subtraction, and multiplication
For operands of one integer identity T:
| Policy | Addition example | Result |
|---|---|---|
| Required | myLeft + myRight |
Exact T; panic when unrepresentable |
| Optional | myLeft +? myRight |
T?; absent when unrepresentable |
| Wrapping | myLeft +% myRight |
Modular T |
| Saturating | myLeft +\| myRight |
T clamped to its nearest bound |
| Combined report | myLeft +! myRight |
Wrapped value, saturated value, and overflow status |
| Wrapped report | myLeft +!% myRight |
Wrapped T plus overflow status |
| Saturated report | myLeft +!\| myRight |
Saturated T plus overflow status |
Subtraction and multiplication use the corresponding forms and behavior.
Each concrete integer identity receives compiler-hidden report identities shared across operations with the same report policy and schema. The wrapped and saturated specialized policies each use:
// Conceptual compiler-hidden identity for one policy and T.
<hidden report type> :: type {
value : T
overflowed : Boolean
}
The combined policy uses:
<hidden combined report type> :: type {
wrapped : T
saturated : T
overflowed : Boolean
}
T means the selected integer identity, not the default Integer role.
Through the protected presence/status behavior:
?reportmeans no overflow; and!reportmeans overflow.
The report type is anonymous on the caller-facing source surface but has one
stable compiler-owned identity. Addition, subtraction, and multiplication may
return the same hidden identity when their concrete T, policy, and schema
match. Another integer identity receives another report type. A caller may use
type of to create a visible alias.
Every generated report defaults to compatible strict. A coincidentally shaped
programmer type does not acquire the report’s protected ?/! behavior. See
Zax structural shapes and compatibility.
Signedness counterpart
Pre-unary + requests the equal-width opposite-signedness counterpart:
myUnsigned : U8 = 100
mySigned := +myUnsigned // I8 value 100
| Policy | Behavior |
|---|---|
+myValue |
Exact counterpart; panic when unrepresentable |
+?myValue |
Optional counterpart; absent when unrepresentable |
+%myValue |
Preserve the logical-width bit pattern |
+\|myValue |
Clamp to the counterpart’s nearest bound |
+!myValue |
Combined counterpart report |
Exact intrinsic types derive the counterpart by changing signedness at equal logical width.
Named role pairs such as Small/USmall and FastI16/FastU16 return the
declared paired identity.
One-sided roles such as Word return the unnamed exact intrinsic counterpart
and leave their role identity.
For an uncommitted integer, pre-unary + toggles sign intent: unknown becomes
unsigned, unsigned becomes signed, and signed becomes unsigned. That
pre-commitment behavior is defined by
Zax integer literals and realization.
For a concrete integer, the counterpart behavior in this section applies.
Negation and magnitude
Negation
Protected signed integers support:
-myValue
-%myValue
-|myValue
-?myValue
-!myValue
-!%myValue
-!|myValue
The minimum signed value has no positive value in the same type:
- required negation panics;
- wrapping negation retains the minimum value’s bit pattern;
- saturating negation returns the signed maximum;
- optional negation is absent; and
- reporting forms return the selected policy value and overflow status.
Protected unsigned integers have no ordinary unary negation.
Magnitude
| Policy | Form | Signed minimum behavior |
|---|---|---|
| Required | \|myValue\| |
Panic |
| Wrapping | \|%myValue\| |
Retain minimum representation |
| Optional | \|?myValue\| |
Absent |
| Combined report | \|!myValue\| |
Report wrapped/saturated alternatives and overflow |
| Saturating | intent<asymmetric-saturating-magnitude>{ \|\|myValue\| } |
Return the signed maximum |
Unsigned magnitude is the same value. Optional and reporting forms remain available so generic numeric code can use one policy.
The norm-like ||myValue|| form has no protected integer operation.
For every signed value except the minimum, saturating magnitude is the ordinary positive magnitude. For the minimum signed value, it returns the signed maximum. For unsigned values, it returns the same value.
Natural ||myValue| is an intent error because it resembles a malformed norm.
The registered intent category explicitly acknowledges the asymmetric form:
myMagnitude :=
intent<asymmetric-saturating-magnitude>{ ||myValue| }
The acknowledgement contract is defined by Zax intent acknowledgements.
Division and remainder
myQuotient := myDividend / myDivisor
myOptionalQuotient := myDividend /? myDivisor
myRemainder := myDividend % myDivisor
myOptionalRemainder := myDividend %? myDivisor
Required division panics when:
- the divisor is zero; or
- a signed minimum value is divided by
-1.
Optional division is absent for either condition.
Successful signed division truncates toward zero.
Required remainder panics only when the divisor is zero. Signed minimum
remainder -1 is zero. Any other nonzero signed remainder has the dividend’s
sign.
No wrapping, saturating, or reporting division/remainder value forms are currently defined.
Compound arithmetic
Every compound evaluates the destination place and right operand once. It is a
direct operation, not a rewrite through the value operator and =.
| Policy | Addition form | Destination behavior |
|---|---|---|
| Required | += |
Write exact result; panic leaves destination unchanged |
| Optional | +?= |
Write on success; otherwise unchanged |
| Wrapping | +%= |
Always write modular result |
| Saturating | +\|= |
Always write clamped result |
| Combined report | +!= |
Write exact result on success; otherwise unchanged; return report |
| Wrapped report | +!%= |
Always write wrapped result and report overflow |
| Saturated report | +!\|= |
Always write saturated result and report overflow |
Subtraction and multiplication use the same policy suffixes.
Ordinary successful compounds return writable access to the updated destination.
That access is discardable, so total += delta is a complete statement; see
Zax operators.
Specialized reporting forms return their report, and the report is required. Choosing a reporting form states that the code will inspect it. When no report is wanted, choose the policy directly:
overflowed := total +!%= delta // wrap, and inspect whether it overflowed
total +%= delta // wrap; no report wanted
total +!%= delta // error: the report is required and unused
Division provides /= and /?=. Remainder provides %= and %?= with the
same failure conditions as their value operations.
Increment and decrement
Both pre and post fixities support:
++ ++? ++% ++| ++! ++!% ++!|
-- --? --% --| --! --!% --!|
Required increment/decrement panics at the representable boundary and leaves the destination unchanged. Optional forms update only on success. Wrapping and saturating forms always write their policy result.
Ordinary pre forms return writable access to the updated place. That access is
discardable, so ++myValue is also a complete statement:
myUpdated := ++myValue
Ordinary post forms return the previous value by copy, and that copy is
required. A post form exists to capture the previous value; to change a value
as a statement, use the pre form:
myPrevious := myValue++ // capture the previous value
++myValue // change the value as a statement
myValue++ // error: the previous value is required and unused
Reporting forms return one transition report containing:
- previous
T; - wrapped
T; - saturated
T; and Booleanoverflow status.
Specialized reports contain the previous value, selected policy value, and overflow status. As with reporting compounds, the report is required; the non-reporting forms are the choice when no report is wanted.
Comparison
Same-identity integers support:
myLeft == myRight
myLeft != myRight
myLeft < myRight
myLeft <= myRight
myLeft > myRight
myLeft >= myRight
Each returns Boolean.
Ungrouped comparison chains remain a source intent error under the general operator catalog.
The three-way comparison form <=> has no protected integer result until its
ordering result type is established.
Bitwise operations
Every protected bitwise operation observes exactly the logical bit width. Non-value storage bits never participate.
Value operations
| Operation | Form | Result |
|---|---|---|
| Complement | ~myValue |
Same integer identity |
| AND | myLeft & myRight |
Same integer identity |
| OR | myLeft \| myRight |
Same integer identity |
| XOR | myLeft ^ myRight |
Same integer identity |
| AND-NOT | myLeft &~ myRight |
Same integer identity |
| NAND | myLeft bitwise nand myRight |
Same integer identity |
| XNOR | myLeft bitwise xnor myRight |
Same integer identity |
| NOR | myLeft bitwise nor myRight |
Same integer identity |
| OR-NOT | myLeft bitwise or not myRight |
Same integer identity |
Direct mutation uses ~=, &=, |=, ^=, &~=, and the exact phrase
mutation forms recorded by the general catalog.
Counts and reductions
| Operation | Form | Result |
|---|---|---|
| Population count | #myBits |
T bit count type |
| Leading-zero count | #<myBits |
T bit count type |
| Trailing-zero count | #>myBits |
T bit count type |
| Leading set-bit mask | #~<myBits |
Same integer identity |
| Trailing set-bit mask | #~>myBits |
Same integer identity |
| Reduction AND | #&myBits |
Boolean |
| Reduction OR | #\|myBits |
Boolean |
| Reduction XOR/parity | #^myBits |
Boolean |
| Reduction NAND | #~&myBits |
Boolean |
| Reduction NOR | #~\|myBits |
Boolean |
| Reduction XNOR | #~^myBits |
Boolean |
For zero, leading- and trailing-zero counts return the complete logical width.
Set-bit masks preserve one bit at its original position:
- leading mask preserves the most-significant set bit;
- trailing mask preserves the least-significant set bit; and
- zero produces zero.
Signed mask results retain the signed identity. Preserving a sign-bit mask is a bit-pattern result, not arithmetic overflow.
Dedicated leading/trailing-one counts remain derivable:
myLeadingOnes := #<(~myBits)
myTrailingOnes := #>(~myBits)
Set-bit positions
myLeadingPosition := myBits leading set bit position
myTrailingPosition := myBits trailing set bit position
The result is optional T bit count type.
Position zero is the least-significant bit. Zero has no set-bit position and returns absent.
myPosition := myBits trailing set bit position
if ?myPosition
myShifted := myValue << myPosition.
The associated count payload is directly accepted by the applicable protected shift.
Shifts and rotations
| Operation | Form |
|---|---|
| Left shift | myValue << myCount |
| Type-natural right shift | myValue >> myCount |
| Explicit zero-fill right shift | myValue >>> myCount |
| Rotate left | myValue <<% myCount |
| Rotate right | myValue >>% myCount |
The count is an accepted unsigned integer. T bit count type is always directly
accepted for T.
For logical width W:
- logical shifts by a count at least
Wreturn zero; - signed type-natural right shift sign-fills and returns all sign bits for a
count at least
W; - unsigned type-natural right shift and every
>>>zero-fill; - rotations use
count mod W; - outgoing bits are discarded; and
- the result never widens implicitly.
Compound forms append =.
The exact modulo-count shift phrases reduce the count modulo W before shifting:
myValue shift left modulo myCount
myValue shift right modulo myCount
myValue logical shift right modulo myCount
They are not rotations. Their exact mutation phrases are recorded by the general operator catalog.
Multiword shift/rotate/funnel operations, reversal, and masked extraction/deposit remain future numeric work.
Integer conversion and admission
Exact intrinsic conversion
Plain as may contextually give a number literal its written destination type:
myByte := 55 as U8
myError := 355 as U8 // error: 355 does not fit U8
Sign intent must permit construction of that destination. The optional and narrowing forms require an already concrete receiver because otherwise their apparent policy could not handle contextual construction failure:
myOptional := 55 as U8? // error: optional `as` requires a concrete receiver
myNarrow := 355 narrowing as U8 // error: narrowing requires a concrete receiver
Once the receiver is concrete, the ordinary policies apply:
myWide := myU16 as U32
myOptional := myU16 as U8?
myNarrow := myU16 narrowing as U8
as Destinationrequires a declared type fact or compile-time-known value proving that the exact value fits.as Destination?returns present when the exact value fits and absent otherwise.narrowing as Destinationperforms defined modular conversion.unsafe asis not ordinary integer narrowing.
The narrowing rule is:
Preserve the source integer modulo
2^W, whereWis the destination logical width, then interpret those bits under destination signedness.
Signed widening sign-extends. Unsigned widening zero-extends. Complete optional result behavior is defined by Zax optional values.
Integer identity admission
myLong := Long from myI32
mySmall := Small optional from myU16
myNarrowSmall := Small narrowing from myU16
fromrequires complete source-range containment;optional fromreturns absent when the exact value does not fit; andnarrowing fromapplies modular conversion before creating the admitting integer identity.
Conversion availability follows declared family facts rather than accidental representation equality in one CPU profile.
Restricted identity validation, unchecked admission, unsafe admission, projection, and direct bridges are defined by Zax identity types.
Exact delta and distance
Both operations require the same integer identity and evaluate operands left to right.
delta
myDelta := myLeft delta myRight
delta returns T delta type and produces exact mathematical
myLeft - myRight.
For logical width W, the result type covers:
-(2^W - 1) through +(2^W - 1)
The CPU profile may select the next suitable native width or an optimized
software-emulated width rather than exact W + 1.
delta is unavailable when no language-supported result type covers the range,
including for a maximum-width integer.
distance
myDistance := myLeft distance myRight
distance returns unsigned T distance type and produces exact absolute
difference without intermediate overflow.
For logical width W, its result covers:
0 through 2^W - 1
It remains available at the language maximum.
Neither operation has wrapping, saturating, optional, reporting, compound, or mutation variants.
Pointer delta/distance require future pointer comparability and validity rules.
Assignment and swap
Protected ordinary assignment:
myDestination = mySource
- requires one integer identity;
- evaluates the existing destination once;
- updates through writable access; and
- returns writable access to the destination.
Declaration initialization remains language syntax rather than assignment.
Swap:
myLeft <<>> myRight
- evaluates both writable places left to right;
- requires compatible integer identities;
- exchanges their values;
- returns zero results; and
- treats exact self-swap as a no-op.
Unchecked build contracts
Required operations normally retain their panic checks in every optimization mode.
Required arithmetic representability
An explicit build setting may promise:
Every required arithmetic result is representable by its result type.
It covers required addition/subtraction/multiplication value and compound forms,
increment/decrement, minimum signed negation/magnitude, and signed minimum
divided by -1.
When the promise holds, the operation produces its exact result. If it is violated, the result and surrounding behavior are undefined. The operation does not become implicitly wrapping.
Nonzero divisors
A separate setting may promise:
Every divisor supplied to required division or remainder is nonzero.
It covers /, %, /=, and %=. Violation has undefined behavior.
Both settings:
- are off by default;
- are independent from debug/release optimization mode;
- remain visible in build metadata and tooling;
- retain diagnostics for compile-time-known violations; and
- do not affect optional, wrapping, saturating, reporting, or narrowing forms.
Source-level panic controls are described by safety and analysis; exact build-option syntax and category names remain future analysis-control work.
Costs and diagnostics
Tooling should expose:
- selected integer identity and associated result type;
- required checks or unchecked build contracts;
- optional, wrapping, saturating, reporting, and narrowing policy;
- eager operand order;
- destination mutation and unchanged-on-failure behavior;
- copies, writable references, previous-value snapshots, and reports;
- native versus software-emulated operation;
- concrete endianness and any adaptation cost;
- invalid count type;
- unavailable signed/unsigned form;
- unavailable maximum-width
delta; - unproved exact conversion; and
- failed identity admission.
Diagnostics lead with public/source type names and provide exact specialization detail on demand.
Boundaries and maturity
This catalog is current conceptual design, not formal grammar, a diagnostic contract, or an implementation mapping.
Exact forms and precedence remain in the
general operator catalog. Multiword operations,
reversal, masked extraction/deposit, pointer difference validity, panic-helper
and category syntax, and build-option syntax remain future work. Fixed-point
operations, including full precision product, are defined separately by
fixed-point scalars.