Operators¶
Accepted
Accepted for V1 operator spelling, precedence, associativity, contract-backed operator surface, and deferred operator boundaries.
This page records source spelling, precedence, associativity, and lookup boundaries for operators. Operators are listed top to bottom in descending precedence. Semantic rules remain on the feature pages that own the values being operated on.
V1 has a closed contract-backed operator surface. Catalyst does not support arbitrary symbolic operator overloading, but selected built-in source forms lower through canonical prelude contract identities.
Precedence¶
a, b, and c stand for expressions. T and E stand for type expressions.
| Prec. | Operator | Description | Associativity |
|---|---|---|---|
| 1 | (a) |
grouping | none |
| 2 | a(b) |
function or callable call | left-to-right |
a[b] |
indexing or slicing | left-to-right | |
a.b |
member or namespace access | left-to-right | |
a.* |
pointer dereference | left-to-right | |
a.? |
forced optional unwrap | left-to-right | |
| 3 | &a |
address-of | prefix |
try a |
error propagation | prefix | |
not a |
boolean negation | prefix | |
-a |
numeric negation | prefix | |
| 4 | a * b, a / b, a % b |
multiplication, division, remainder | left-to-right |
| 5 | a + b, a - b |
addition and subtraction | left-to-right |
| 6 | a..b, a..=b |
half-open and inclusive-end range | non-associative |
| 7 | a < b, a <= b, a > b, a >= b |
ordering comparison | non-associative |
| 8 | a == b, a != b |
equality comparison | non-associative |
| 9 | a and b |
short-circuit boolean or predicate conjunction | left-to-right |
| 10 | a or b |
short-circuit boolean or predicate disjunction | left-to-right |
| 11 | a orelse b |
optional defaulting unwrap | left-to-right |
a catch as err { ... }, a catch b |
error handling | left-to-right | |
| 12 | a = b |
assignment | non-associative |
When two operator families do not have a documented precedence relationship, code should use parentheses. The parser or sema should reject unclear mixes rather than silently choosing a surprising grouping.
Parsing, not availability
The table is a source parsing reference, not a promise that every operator is available for every type. Availability and lowering are owned by the relevant semantic pages.
Precedence and associativity are compile-time parsing concepts. They do not define runtime evaluation order. Evaluation order rules are documented on feature pages when they matter for moves, resource cleanup, or side effects.
Move¶
move place is a special ownership-transfer form, not a generic prefix operator over arbitrary expressions. The operand must be a movable local place as documented in Move Expressions.
When the moved value is used as a receiver, parenthesize the move:
var erased = (move concrete_box).into_dyn(Iterator(i32))
Moving the result of a method call is invalid in V1:
move concrete_box.into_dyn(Iterator(i32))
Type Operators¶
Type-level operator-like forms are parsed in type-expression contexts:
| Form | Description | Canonical semantics |
|---|---|---|
?T |
optional type | Optional Types |
T!E, T! |
error-return type | Errors |
A & B |
type or constraint intersection | Type System |
A | B |
enum union or error-set union | Enums and Errors |
These forms are documented separately from expression precedence because they appear where the parser expects types.
Composed error-set expressions in T!E must be parenthesized for readability:
Module!(ReadError | ParseError)
Unparenthesized mixes such as Module!ReadError | ParseError are rejected with a diagnostic that suggests the parenthesized form.
Contract-Backed Source Forms¶
These expression operators and operator-like source forms lower through canonical prelude contracts:
| Source form | Contract family | Canonical semantics |
|---|---|---|
a == b, a != b |
PartialEq(Rhs) |
Equality and Ordering Contracts |
a < b, a <= b, a > b, a >= b |
PartialOrd(Rhs) |
Equality and Ordering Contracts |
a + b, a - b, a * b, a / b, a % b, -a |
Add(Rhs, Out), Sub(Rhs, Out), Mul(Rhs, Out), Div(Rhs, Out), Rem(Rhs, Out), Neg(Out) |
Arithmetic Contracts |
a[i] |
Indexable(T) |
Indexing and Sequence Contracts |
a[i] = value |
MutableIndexable(T) |
Indexing and Sequence Contracts |
Loop source selection is not an expression operator, but it is also contract-backed: for item in xs resolves through Iterator(Item), Iterable(Item), or MutableIterable(Item) as documented in Iterator Loop Sources.
Operator lowering is tied to canonical prelude contract identities, not arbitrary local bindings with the same names. Shadowing a prelude contract name does not change source-operator lowering.
Assignment¶
Assignment is a non-overloadable expression form:
place = expression
The right-hand side evaluates before the store. The assignment expression result is the assigned value observed through the destination place. If that result is consumed by value, ordinary copy and move rules apply.
Assignment does not associate:
a = b = c
Use explicit grouping when the result of one assignment is intentionally assigned again:
a = (b = c)
Assignments in conditions and assignment results bound to named locals are lintable because they are often accidental. Assignment to resource-owning places participates in ownership/live-overwrite.
Assignment-like syntax in declarations, aggregate construction, and destructuring is owned by those specific source forms:
binding = exprin declarations.field = exprin aggregate constructionname = source_namein destructuring patterns
Compound assignment forms such as +=, -=, *=, /=, and %= are deferred from V1. Future compound assignment sugar and optional mutating override contracts are tracked in CEP-0055: Compound Assignment Operators.
Associativity¶
Arithmetic operators associate left-to-right:
a - b - c // (a - b) - c
Range operators are non-associative:
a..b..c // error
Comparison and equality operators do not chain:
a < b < c // error
Write the boolean relationship explicitly:
a < b and b < c
No implicit chaining
Range, ordering, and equality operators do not chain. Use parentheses or explicit boolean operators when combining comparisons.
Boolean and and or short-circuit left-to-right. For fact-bearing Type.Predicate values, and may preserve positive narrowing facts for the right-hand side and true branch; or and not have boolean behavior but do not add positive or negative narrowing facts in V1. See Predicate Reflection and Conditional Declarations.
Ranges¶
Range operators have lower precedence than arithmetic, so endpoint expressions can be written naturally:
a + 1..b - 1 // (a + 1)..(b - 1)
start..end creates a half-open range. start..=end creates an inclusive-end range.
Comparisons should not chain through ranges. Ambiguous expressions should require parentheses and produce diagnostics that ask for explicit grouping:
(a..b) == range
a < (b..c) // error unless a future type intentionally supports that comparison
Omitted-bound range forms are valid only in slicing contexts in V1:
items[start..]
items[..end]
items[..]
Standalone omitted-bound ranges are deferred.
Equality and Ordering¶
Equality and ordering are contract-backed source syntax:
a == b
a != b
a < b
a <= b
a > b
a >= b
These operators are not globally available for every type. Availability and lowering are documented in Equality and Ordering Contracts.
Comparison results involving unordered primitive floats follow the partial-order contract semantics: <, <=, >, and >= return false when operands are unordered.
Boolean Operators¶
Boolean operators use words, not symbolic spellings:
not ready
ready and valid
ready or fallback_allowed
and and or short-circuit. not applies to the following boolean operand.
The symbolic forms &&, ||, and !condition are not V1 boolean operators. Keeping boolean logic word-based makes it read consistently with and and or, and keeps ! visually reserved for error-return type syntax such as T!E and T!.
Optional Operators¶
orelse and .? are optional-specific source forms:
const label = maybe_label orelse "unknown"
const value = maybe_value.?
a orelse b unwraps one optional layer or evaluates the fallback when a is null. a.? forces an optional unwrap and traps on null in Checked safety mode. Optional type semantics, short-circuit behavior, and trap behavior are documented in Optional Types.
Arithmetic¶
Arithmetic operators are contract-backed source syntax:
a + b
a - b
a * b
a / b
a % b
-a
These operators are not globally available for every type. Availability, lowering, result-type selection, primitive numeric conformances, and user implementation rules are documented in Arithmetic Contracts.
Unary numeric negation applies to signed integers and floats. It is not part of a numeric literal token. A suffixed unsigned literal remains unsigned before unary negation is checked:
-1u8
Primitive integer overflow and floating-point type availability are documented in Built-In Types. Numeric coercions are documented in Numeric Types.
Bitwise and shift operator spellings are not part of the V1 expression operator surface. Their future contract-backed shape is tracked in CEP-0056: Bitwise and Shift Operators.
Related Details¶
- Literals: signs, numeric literal suffixes, leading-dot forms, and aggregate field designators.
- Expected-Type Shorthand:
.caseexpressions and contextual aggregate literals. - Arrays, Slices, Ranges, and Indexing: indexing, slicing, and range semantics.
- Equality and Ordering Contracts: operator availability and lowering for
==,!=,<,<=,>, and>=. - Arithmetic Contracts: operator availability, lowering, result-type selection, primitive conformances, and user-defined arithmetic impls.
- Error Handling:
tryandcatch. - Move Expressions: ownership-transfer expression syntax.