Skip to content
Pre-Release: Fe is under active development. This documentation covers the upcoming release. Follow progress on GitHub

Operators & Expressions

Fe provides a comprehensive set of operators for arithmetic, comparison, logic, and bit manipulation, along with various expression types for building complex computations.

Arithmetic operators work on numeric types.

OperatorDescriptionExample
+Additiona + b
-Subtractiona - b
*Multiplicationa * b
/Divisiona / b
%Modulo (remainder)a % b
**Exponentiationa ** b
let sum: u256 = 10 + 5 // 15
let diff: u256 = 10 - 5 // 5
let product: u256 = 10 * 5 // 50
let quotient: u256 = 10 / 3 // 3 (integer division)
let remainder: u256 = 10 % 3 // 1
let power: u256 = 2 ** 8 // 256

Division between integers performs integer division, truncating toward zero:

let result: i256 = 7 / 2 // 3, not 3.5
let neg: i256 = -7 / 2 // -3

Comparison operators return bool values.

OperatorDescriptionExample
==Equal toa == b
!=Not equal toa != b
<Less thana < b
<=Less than or equala <= b
>Greater thana > b
>=Greater than or equala >= b
let x: u256 = 5
let y: u256 = 10
let is_equal = x == y // false
let is_not_equal = x != y // true
let is_less = x < y // true
let is_less_eq = x <= 5 // true
let is_greater = x > y // false
let is_greater_eq = y >= 10 // true

Logical operators work on bool values.

OperatorDescriptionExample
&&Logical ANDa && b
||Logical ORa || b
!Logical NOT!a
let a = true
let b = false
let and_result = a && b // false
let or_result = a || b // true
let not_result = !a // false

Logical operators use short-circuit evaluation:

  • && stops evaluating if the left operand is false
  • || stops evaluating if the left operand is true
// If is_valid is false, expensive_check() won't be called
if is_valid && expensive_check() {
// ...
}
// If has_default is true, compute_value() won't be called
let value = has_default || compute_value()

Bitwise operators manipulate individual bits of integer values.

OperatorDescriptionExample
&Bitwise ANDa & b
|Bitwise ORa | b
^Bitwise XORa ^ b
~Bitwise NOT~a
<<Left shifta << n
>>Right shifta >> n
let a: u8 = 0b1100
let b: u8 = 0b1010
let and_bits: u8 = a & b // 0b1000 (8)
let or_bits: u8 = a | b // 0b1110 (14)
let xor_bits: u8 = a ^ b // 0b0110 (6)
let not_bits: u8 = ~a // inverts all bits
let shifted_left: u8 = a << 2 // 0b110000 (48)
let shifted_right: u8 = a >> 2 // 0b0011 (3)
const FLAG: u8 = 0b0010
// Check if a bit is set
let has_flag = (value & FLAG) != 0
// Set a bit
let with_flag = value | FLAG
// Clear a bit
let without_flag = value & ~FLAG
// Toggle a bit
let toggled = value ^ FLAG

Unary operators take a single operand.

OperatorDescriptionExample
+Unary plus (identity)+x
-Negation-x
!Logical NOT!flag
~Bitwise NOT~bits
let x: i256 = 42
let negative: i256 = -x // -42
let positive: i256 = +x // 42 (no change)
let flag = true
let inverted = !flag // false
let bits: u8 = 0b11110000
let flipped: u8 = ~bits // 0b00001111

Use = to assign a value to a mutable variable:

let mut x: u256 = 10
x = 20 // x is now 20

Compound assignment operators combine an operation with assignment:

OperatorEquivalent toDescription
+=x = x + yAdd and assign
-=x = x - ySubtract and assign
*=x = x * yMultiply and assign
/=x = x / yDivide and assign
%=x = x % yModulo and assign
&=x = x & yBitwise AND and assign
|=x = x | yBitwise OR and assign
^=x = x ^ yBitwise XOR and assign
<<=x = x << yLeft shift and assign
>>=x = x >> yRight shift and assign
let mut count: u256 = 10
count += 5 // count is now 15
count -= 3 // count is now 12
count *= 2 // count is now 24
let mut flags: u8 = 0b0000
flags |= 0b0001 // Set bit 0
flags |= 0b0100 // Set bit 2
// flags is now 0b0101

Fe is an expression-oriented language. Most constructs produce values.

A block { } is an expression that evaluates to its last expression:

let result: u256 = {
let a: u256 = 10
let b: u256 = 20
a + b // no semicolon - this is the block's value
}
// result is 30

Call functions with parentheses:

let value = compute(10, 20)
let result = process(data, flag: true) // with labeled argument

Call methods on values using dot notation:

let doubled = counter.multiply(by: 2)
let incremented = counter.add(amount: 10)

Access struct fields with dot notation:

let x = point.x
let name = user.profile.name

Access array and tuple elements by index:

let first = arr[0]
let third = arr[2]
let x = tuple.0
let y = tuple.1

Create tuples with parentheses:

let point: (u256, u256) = (10, 20)
let triple: (u256, bool, String<5>) = (1, true, "hello")
let unit: () = () // empty tuple (unit type)

Create arrays with brackets:

let numbers: [u256; 5] = [1, 2, 3, 4, 5]
let flags: [bool; 3] = [true, false, true]
// Repeat syntax: [value; count]
let zeros: [u256; 10] = [0; 10] // array of 10 zeros

if is an expression that returns a value:

let max = if a > b { a } else { b }
let description = if count == 0 {
"none"
} else if count == 1 {
"one"
} else {
"many"
}

match is an expression for pattern matching:

let result = match value {
0 => "zero"
1 => "one"
_ => "other"
}

Use parentheses to control evaluation order:

let result: u256 = (a + b) * c
let complex: u256 = ((x + y) * z) / w

Operators are evaluated according to their precedence. Higher precedence operators bind tighter.

PrecedenceOperatorsAssociativity
Highest(), ., []Left to right
Unary +, -, !, ~Right to left
**Right to left
*, /, %Left to right
+, -Left to right
<<, >>Left to right
&Left to right
^Left to right
|Left to right
==, !=, <, <=, >, >=Left to right
&&Left to right
||Left to right
Lowest=, +=, -=, etc.Right to left

When in doubt, use parentheses to make your intent clear:

// These are equivalent, but the second is clearer
let result: u256 = a + b * c
let result: u256 = a + (b * c)
CategoryOperators
Arithmetic+, -, *, /, %, **
Comparison==, !=, <, <=, >, >=
Logical&&, ||, !
Bitwise&, |, ^, ~, <<, >>
Assignment=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=