Expressions

Joule is expression-oriented. Most constructs return a value, including if, match, and blocks.

Literals

42          // integer (i32)
3.14        // float (f64)
true        // bool
'A'         // char
"hello"     // String

Integer Literal Suffixes

42i8    42i16   42i32   42i64   42isize
42u8    42u16   42u32   42u64   42usize

Float Literal Suffixes

3.14f32     3.14f64

Arithmetic Operators

OperatorOperationTypes
+Additionintegers, floats, String concatenation
-Subtractionintegers, floats
*Multiplicationintegers, floats
/Divisionintegers, floats
%Remainderintegers
**Exponentiationintegers, floats (right-associative)

Comparison Operators

OperatorOperation
==Equal
!=Not equal
<Less than
>Greater than
<=Less or equal
>=Greater or equal

All comparison operators return bool.

Logical Operators

OperatorOperation
&&Logical AND (short-circuit)
||Logical OR (short-circuit)
!Logical NOT

Bitwise Operators

OperatorOperation
&Bitwise AND
|Bitwise OR
^Bitwise XOR
~Bitwise NOT
<<Left shift
>>Right shift

Pipe Operator

The pipe operator |> passes the result of the left-hand expression as the first argument to the right-hand function:

// Without pipe
let result = process(transform(parse(input)));

// With pipe -- reads left to right
let result = input |> parse |> transform |> process;

Pipe with Multi-Argument Functions

When the right-hand side is a call with arguments, the piped value is inserted as the first argument:

let result = data
    |> filter(|x| x > 0)
    |> map(|x| x * 2)
    |> take(10);

Pipe Precedence

The pipe operator has lower precedence than all other operators except assignment. It is left-associative:

// These are equivalent:
a |> f |> g
g(f(a))

Assignment

let mut x = 0;
x = 42;

Compound assignment is not supported. Use x = x + 1 instead of x += 1.

Block Expressions

A block evaluates to its last expression:

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

If Expressions

if is an expression and returns a value:

let max = if a > b { a } else { b };

Without else, the type is ():

if condition {
    do_something();
}

Chained:

if x > 0 {
    "positive"
} else if x < 0 {
    "negative"
} else {
    "zero"
}

Match Expressions

Exhaustive pattern matching:

let name = match color {
    Color::Red => "red",
    Color::Green => "green",
    Color::Blue => "blue",
};

See Patterns for pattern syntax.

Loops

While Loop

while condition {
    body();
}

For Loop

for item in collection {
    process(item);
}

Loop (Infinite)

loop {
    if done() {
        break;
    }
}

Break and Continue

loop {
    if skip_this() {
        continue;
    }
    if finished() {
        break;
    }
}

Function Calls

let result = add(1, 2);

Method Calls

let len = string.len();
let upper = string.to_uppercase();

Field Access

let x = point.x;
let name = person.name;

Index Access

let first = vec[0];
let char = string[i];

Struct Construction

let p = Point { x: 3.0, y: 4.0 };

Enum Variant Construction

let c = Shape::Circle { radius: 5.0 };
let ok = Result::Ok(42);

Return

Explicit return from a function:

fn find(items: Vec<i32>, target: i32) -> Option<i32> {
    let mut i = 0;
    while i < items.len() {
        if items[i] == target {
            return Option::Some(items[i]);
        }
        i = i + 1;
    }
    Option::None
}

Type Cast

let x = 42i32 as f64;
let y = offset as usize;