Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Arithmetic and Logic

Cambrian provides arithmetic, comparison, logical, and bitwise operators. A distinguishing feature is its dual arithmetic mode: checked (default) and wrapping, giving explicit control over overflow behavior.

Arithmetic Operators

OperatorOperationExample
+Additiona + b
-Subtractiona - b
*Multiplicationa * b
/Divisiona / b
%Remaindera % b

These operators work on all integer types (u8 through u128, i8 through i128, U256).

let total = price * quantity;
let fee = amount * 3 / 100;
let remainder = total % batch_size;

Checked vs. Wrapping Arithmetic

By default, arithmetic in Cambrian is checked – operations that overflow or underflow will revert the transaction. This is the safe default for financial computations.

Checked Operators (Default)

Standard operators (+, -, *) perform checked arithmetic:

let sum = a + b;       // reverts on overflow
let diff = a - b;      // reverts if b > a for unsigned types

/ and % revert if the divisor is zero (Panic(0x12) on EVM). There is no wrapping division.

On --target lean, the source meaning is still checked, but the default Lean model of +/-/* wraps unless you set lean.numerics: overflow-panic. See Checked vs Wrapping Arithmetic.

Wrapping Operators

When you intentionally want modular arithmetic (values wrap around on overflow), use the %-suffixed operators:

let wrapped_sum = a +% b;   // wraps on overflow
let wrapped_diff = a -% b;  // wraps on underflow
let wrapped_prod = a *% b;  // wraps on overflow

When to Use Each

ScenarioUse
Token balances, financial mathChecked (+, -, *)
Hash computations, bit manipulationWrapping (+%, -%)
Counter that should wrap at maxWrapping (+%)
Any case where overflow is a bugChecked (default)

Example showing both in the same entity:

pure fn safe_add(a: U256, b: U256) -> U256 {
    a + b  // checked -- reverts if overflow
}

pure fn hash_combine(a: u64, b: u64) -> u64 {
    (a *% 31) +% b  // wrapping -- intentional modular arithmetic
}

Comparison Operators

OperatorMeaningExample
==Equala == b
!=Not equala != b
<Less thana < b
<=Less than or equala <= b
>Greater thana > b
>=Greater than or equala >= b

All comparison operators return bool. They are commonly used in where clauses and if conditions:

routes {
    withdraw(amount: U256)
        where m_balance >= amount : throw 100
        && msg::sender == m_owner : throw 101
    => [
        ~> msg::sender with { value: amount }
    ]
}

Logical Operators

OperatorMeaningExample
&&Logical ANDa && b
||Logical ORa || b
!Logical NOT!a

Logical operators work on bool values and short-circuit: && stops at the first false, and || stops at the first true.

macro can_withdraw(amount: U256) -> bool = {
    m_balance >= amount && msg::sender == m_owner
}

Bitwise Operators

OperatorOperationExample
&Bitwise ANDa & b
|Bitwise ORa | b
^Bitwise XORa ^ b
<<Left shifta << n
>>Right shifta >> n

Bitwise operators work on integer types and are useful for flag manipulation and low-level computations:

let flags = 0b1010;
let has_flag = (flags & 0b0010) != 0;
let shifted = value << 8;

Operator Precedence

From highest to lowest precedence:

PrecedenceOperators
Highest! (unary)
*, /, %
+, -
<<, >>
&
^
|
==, !=, <, <=, >, >=
&&
Lowest||

Use parentheses to override precedence when the intent is not obvious:

let result = (a + b) * (c - d);
let check = (x > 0) && (y < max);