> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arcium.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Operations

> Complete reference for supported operations, expressions, and patterns in Arcis MPC circuits

Arcis supports many of Rust's native operations and extends them for encrypted data, allowing you to write private computations using familiar Rust syntax. See the tables below for a detailed list of supported and unsupported operations.

<Tip>
  **Use this page when** you need to check if a specific operation is supported in Arcis circuits.
</Tip>

## Quick summary

**Works:** `if/else`, `if let`, `match`, `for` loops, arithmetic, comparisons, iterators (except filter)

**Doesn't work:** `while`, `loop`, `break`, `continue`, `return`, `let ... else`, `.filter()`

See tables below for full details.

### Table of contents

* [Expression support](#expression-support)
  * [Binary expressions](#binary-expressions)
  * [Unary expressions](#unary-expressions)
  * [Casts](#cast-expressions)
  * [Literals](#literal-expressions)
  * [Methods](#method-calls)
  * [Paths](#paths)
* [Item support](#item-support)
* [Pattern support](#pattern-support)
  * [Pattern matching](#pattern-matching)

## Expression support

| Expression Name | Example | Support | Comments |
| - | - | - | - |
| Array literal | `[a, b]` | Supported | |
| Assignment | `a = b;` | Supported | |
| Async block | `async { ... }` | Unsupported | |
| Await | `foo().await` | Unsupported | |
| Binary expression | `a + b` | Partial Support | [See table below](#binary-expressions) for supported binary expressions. |
| Block expression | `{ ... }` | Supported | |
| Break | `break;` | Unsupported | |
| Function call | `f(a, b)` | Partial Support | [See table below](#function-calls) for supported functions. |
| Casts | `a as u16` | Partial Support | [See table below](#cast-expressions) for supported conversions. |
| Closures | `\|a, b \| a + b` | Supported | |
| Const block | `const { ... }` | Supported | |
| Continue | `continue;` | Unsupported | |
| Field access/set | `obj.field` | Supported | |
| For loop | `for i in expr { ... }` | Supported | `expr` must have a length known at compile-time. |
| If | `if cond { ... } else { ... }` | Supported | Complexity is O(`then_block + else_block`). |
| Indexing | `a[idx]` | Supported | Complexity is O(`a.len()`) if `idx` isn't compile-time known (all positions are checked to hide which index was accessed). Slicing accepts `a[2..5]`, `a[2..=4]`, `a[2..]`, `a[..5]`, `a[..=4]`, and `a[..]` when each specified bound is compile-time known. |
| If let | `if let Some(x) = ...` | Partial Support | [See pattern matching](#pattern-matching). Let chains require Rust edition 2024. |
| Literals | `1u128` | Partial Support | [See table below](#literal-expressions) for supported literals. |
| Loops | `loop { ... }` | Unsupported | MPC circuits have fixed structure: variable iteration counts would require dynamic circuit size. Use `for` with compile-time bounds instead. |
| Macros | `println!("{}", q)` | Partial Support | [See table below](#macros) for supported macros. |
| Match | `match n { ... }` | Partial Support | [See pattern matching](#pattern-matching). Last arms cannot have guards. |
| Method calls | `x.foo(a, b)` | Partial Support | [See table below](#method-calls) for supported methods. |
| Parentheses | `(a + b)` | Supported | |
| Paths | `Foo::bar` | Partial Support | [See table below](#paths) for supported paths. |
| Ranges | `4..5` | Partial Support | Specified bounds must be compile-time known. `Range` and `RangeInclusive` are fully iterable. `RangeFrom` iterates forward only. `RangeTo`, `RangeToInclusive`, and `RangeFull` are slice-index only. |
| Raw addresses | `&raw const foo` | Unsupported | |
| References | `&mut foo` | Supported | |
| Repeat arrays | `[4u8; 128]` | Supported | |
| Return | `return false;` | Unsupported | |
| Struct literals | `MyStruct { a: 12, b }` | Supported | |
| Try expression | `this_call_can_err()?;` | Unsupported | |
| Tuple literal | `(a, 4, c)` | Supported | |
| Unary expressions | `!x` | Partial Support | [See table below](#unary-expressions) for supported unary expressions. |
| Unsafe | `unsafe { ... }` | Unsupported | |
| While loops | `while x < 64 { ... }` | Unsupported | Cannot be supported as the number of iterations is not known. |

<Note>
  **Why branches count:** In MPC, both sides of non-constant conditional execution are evaluated, including `if`/`else` branches and non-constant `match` arms. The condition only selects which result to use. This ensures the execution pattern does not leak information about the condition value. See [Thinking in MPC](/developers/arcis/mental-model) for details.
</Note>

### Binary expressions

User-defined binary operations are currently unsupported.

| Example | Supported types |
| - | - |
| `a + b` | Integers, floats, `BaseField25519` |
| `a - b` | Integers, floats, `BaseField25519` |
| `a * b` | Integers, floats, `BaseField25519` |
| `a / b` | Integers, floats |
| `a % b` | Integers |
| `a && b` | Booleans |
| `a \|\| b` | Booleans |
| `a ^ b` | Booleans, integers |
| `a & b` | Booleans, integers |
| `a \| b` | Booleans, integers |
| `a << b` | Integers, if `b` is known at compile time. |
| `a >> b` | Integers, if `b` is known at compile time. |
| `a == b` | All. Use `derive(PartialEq)` for structs. |
| `a != b` | All. Use `derive(PartialEq)` for structs. |
| `a < b` | Booleans, integers, floats, `BaseField25519` |
| `a <= b` | Booleans, integers, floats, `BaseField25519` |
| `a >= b` | Booleans, integers, floats, `BaseField25519` |
| `a > b` | Booleans, integers, floats, `BaseField25519` |
| `a += b` | Integers, floats, `BaseField25519` |
| `a -= b` | Integers, floats, `BaseField25519` |
| `a *= b` | Integers, floats, `BaseField25519` |
| `a /= b` | Integers, floats |
| `a %= b` | Integers |
| `a ^= b` | Booleans, integers |
| `a &= b` | Booleans, integers |
| `a \|= b` | Booleans, integers |
| `a <<= b` | Integers, if `b` is known at compile time. |
| `a >>= b` | Integers, if `b` is known at compile time. |

<Note>
  `BaseField25519` does **not** support `/`, `%`, `>>`, `<<`, `&`, `|`, or `^`. Use `.field_division()` or `.euclidean_division()` for division on field elements. See [BaseField25519 Operations](/developers/arcis/primitives#basefield25519-operations).
</Note>

### Unary expressions

User-defined unary operations are currently unsupported.

| Example | Supported types |
| - | - |
| `!x` | Booleans (logical NOT), integers (bitwise NOT) |
| `-x` | Signed integers, floats, `BaseField25519` |
| `*x` | `&T`, `&mut T`, `Box<T>` |

### Cast expressions

`a as MyType` is only supported:

| From Type | To Type |
| - | - |
| integer type | integer type |
| `bool` | integer type |
| integer type | `bool` |
| `&...&T` | `&T` |

### Function calls

The following function calls are supported:

* user-defined function calls (without recursion)
* `ArcisRNG::bool()` to generate a boolean.
* `ArcisRNG::gen_uniform::<T>()` to generate a uniform value of type T (bool, integer, or combination). Requires explicit type parameter.
* `ArcisRNG::gen_integer_from_width(width: usize) -> u128`. Generates a secret integer between 0 and 2^width - 1 included.
* `ArcisRNG::gen_public_integer_from_width(width: usize) -> u128`. Generates a public integer between 0 and 2^width - 1 included.
* `ArcisRNG::gen_integer_in_range(min: u128, max: u128, n_attempts: usize) -> (u128, bool)`. Generates a random integer in `[min, max]` using rejection sampling. **`n_attempts` must be compile-time known**. Returns `(result, success)` where `success=false` indicates all attempts were rejected. With `n_attempts=24`, failure probability is `<2^-24`.
* `ArcisRNG::shuffle(slice)` on slices. Complexity is in `O(n*log³(n) + n*log²(n)*sizeof(T))`.
* `Mxe::get()` to be able to create MXE-owned secret data.
* `Shared::new(arcis_public_key)` to share private data with `arcis_public_key`.
* `ArcisX25519Pubkey::from_base58(base58_byte_string)` to create a public key from a base58-encoded address.
* `ArcisX25519Pubkey::from_uint8(u8_byte_slice)` to create a public key from a Uint8 array.
* `SolanaPublicKey::from_serialized(value)` to create a Solana public key from serialized form.
* `SolanaPublicKey::from_base58(byte_string)` to create a Solana public key from base58.
* `ArcisMath::sigmoid(x)` for the sigmoid activation function.
* `LogisticRegression::new(coef, intercept)` for logistic regression models.
* `LinearRegression::new(coef, intercept)` for linear regression models.
* `Pack::new(value)` to bit-pack data for onchain storage (multiple small values fit into fewer field elements).
* `ArcisX25519Pubkey::new_from_x(x: BaseField25519)` to create a public key from its Curve25519 Montgomery X-coordinate.
* `ArcisX25519Pubkey::to_x() -> BaseField25519` to extract the Montgomery X-coordinate from a public key.
* `BaseField25519::from_u8(x)` ... `BaseField25519::from_u128(x)` to convert unsigned integers to field elements. Signed variants (`from_i8` ... `from_i128`) and `from_bool`, `from_usize`, `from_isize` also available.
* `BaseField25519::power_of_two(exp)` to compute `2^exp` as a field element.

### Literal expressions

| Example | Support |
| - | - |
| `"foo"` | Unsupported |
| `b"foo"` | Supported |
| `c"foo"` | Unsupported |
| `b'f'` | Supported |
| `'a'` | Unsupported |
| `1` | Supported |
| `1u16` | Supported |
| `1f64` | Supported |
| `1.0e10f64` | Supported |
| `true` | Supported |

### Macros

The following macros are supported:

* `debug_assert!`, `debug_assert_ne!`, `debug_assert_eq!` to assert conditions during debugging. They do not change instruction behavior.
* `eprint!`, `eprintln!`, `print!`, `println!` to print debug output. They do not change instruction behavior.
* `matches!(expr, pattern)` to test a pattern and return `bool`. See [Pattern support](#pattern-support).
* `arcis_static_panic!(message)` to fail compilation when the branch is reached. Useful for enforcing constraints that must be known before circuit generation.
* `include_bytes!("file_path")` to include raw bytes from a file in Arcis circuits.
* `include!("file_path")` to include a file in item position (not expression position).
* `assert_current_module!(crate::path::to::module)` to enable `crate::` absolute paths within the current module. Place at the top of any module that needs to reference items via absolute paths.
* `encrypted_mod!("path/to/module.rs")` or `encrypted_mod!("path/to/module.rs", alias_name)` to use another file as a module within an `#[encrypted]` module. The target file must use the `#[encrypted_library]` attribute. Items are accessible via the filename stem (or alias) as a namespace, e.g., `module_name::ITEM`.

Example usage:

```rust theme={null}
const ARRAY_LEN: usize = 3; // Change to 1 and the example will not compile.

fn second_element(arr: &[u8]) -> u8 {
    if arr.len() < 2 {
        arcis_static_panic!("Array must have at least 2 elements");
    }
    arr[1]
}

#[instruction]
fn reveal_second_element(input: Enc<Shared, Pack<[u8; ARRAY_LEN]>>) -> u8 {
    let array = input.to_arcis().unpack();
    second_element(&array).reveal()
}
```

<Note>
  `arcis_static_panic!` triggers at compile time when the Arcis compiler evaluates the branch. Try changing `ARRAY_LEN` to `1` above: the compile error demonstrates how this macro enforces constraints that must be validated before circuit generation.
</Note>

### Method calls

The following method calls are supported:

* user-defined method calls (with generics but without recursion)
* `.clone()` on all `Clone` objects.
* `.len()`, `.is_empty()`, `.swap(a, b)`, `.fill(value)`, `.reverse()`, `.iter()`, `.iter_mut()`, `.into_iter()`, `.windows(width)`, `.copy_from_slice(src)`, `.clone_from_slice(src)`, `.split_at(mid)`, `.split_at_mut(mid)`, `.rotate_left(mid)`, `.rotate_right(mid)`, `.contains(item)`, `.starts_with(needle)`, `.ends_with(needle)`, `.as_slice()`, `.as_mut_slice()` on arrays and slices.
* `.first()`, `.first_mut()`, `.last()`, `.last_mut()`, `.get(index)`, `.get_mut(index)`, `.split_first()`, `.split_first_mut()`, `.split_last()`, `.split_last_mut()`, `.first_chunk::<N>()`, `.first_chunk_mut::<N>()`, `.last_chunk::<N>()`, `.last_chunk_mut::<N>()`, `.split_first_chunk::<N>()`, `.split_first_chunk_mut::<N>()`, `.split_last_chunk::<N>()`, `.split_last_chunk_mut::<N>()` on arrays and slices. These return `Option`.
* `.as_array::<N>()`, `.as_mut_array::<N>()` on slices (requires Rust 1.93+). These return `Option`.
* `.map(f)`, `.each_ref()`, `.each_mut()` on arrays.
* `.sort()` on arrays of integers. Complexity is in `O(n*log²(n)*bit_size)`.
* `.sort_by_cached_key(f)` on arrays and slices, where `f` returns an integer key (any `uN` or `iN` with N in 8, 16, 32, 64, 128). Complexity is in `O(n*log²(n)*bit_size)`.
* `.enumerate()`, `.chain(other)`, `.cloned()`, `.copied()`, `.count()`, `.rev()`, `.zip(other)`, `.map(func)`, `.for_each(func)`, `.fold(init, func)`, `.sum()`, `.product()`, `.collect::<Box<[_]>>()` on iterators.
* `.take(n)`, `.skip(n)`, `.step_by(n)` on iterators when `n` is compile-time known.
* `.reveal()` if not inside a conditionally executed block (`if`/`else`, non-constant `match` arm, or guard)
* `.to_arcis()` on `Enc`s
* `.from_arcis(x)` on `Owner`s (objects of types `Mxe` or `Shared`) if not inside a conditionally executed block (`if`/`else`, non-constant `match` arm, or guard)
* `.abs()`, `.min(x)`, `.max(x)` on integers and floats
* `.abs_diff(other)`, `.is_positive()`, `.is_negative()`, `.div_ceil(other)` on integers
* `.to_le_bytes()`, `.to_be_bytes()`, `.wrapping_add(rhs)`, `.wrapping_sub(rhs)`, `.wrapping_mul(rhs)` on typed integers (does not work on integers whose type the interpreter does not know)
* `.exp()`, `.exp2()`, `.ln()`, `.log2()`, `.sqrt()` on floats.
* `.set(val)`, `.swap(other)`, `.update(f)`, `.replace(val)`, `.into_inner()`, `.get()`, `.get_mut()` on `Cell`.
* `.unpack()` on `Pack<T>` to extract the original value from packed storage.
* `Option<T>` combinators: `.is_some()`, `.is_none()`, `.is_some_and(f)`, `.is_none_or(f)`, `.unwrap()`, `.unwrap_or(default)`, `.unwrap_or_else(f)`, `.map(f)`, `.map_or(default, f)`, `.map_or_else(default_f, f)`, `.inspect(f)`, `.filter(predicate)`, `.and(other)`, `.and_then(f)`, `.or(other)`, `.or_else(f)`, `.xor(other)`, `.zip(other)`, `.unzip()`, `.flatten()`, `.copied()`, `.cloned()`, `.take()`, `.take_if(predicate)`, `.replace(value)`, `.insert(value)`, `.get_or_insert(value)`, `.get_or_insert_with(f)`.
* `.to_arcis_with_pubkey_and_nonce(pubkey, nonce)` on `EncData<T>` to decrypt when the key is shared across inputs (avoids duplicate decryption gates). See [EncData](/developers/arcis/types#advanced-encdata%3Ct%3E) for details.
* `.data` on `Enc<Owner, T>` to extract only the `EncData<T>` ciphertext for smaller callback payloads.
* `.safe_inverse()` on `BaseField25519` to get the field inverse (returns 0 for inverse of 0).
* `.field_division(divisor)` on `BaseField25519` for field division (returns 0 for division by 0).
* `.euclidean_division(divisor)` on `BaseField25519` for signed Euclidean division (panics on division by 0).
* `.to_u8_unchecked()` ... `.to_u128_unchecked()` on `BaseField25519` to extract as unsigned int. Silently produces incorrect results if value exceeds target range. Signed variants (`to_i8_unchecked` ... `to_i128_unchecked`) and `to_bool_unchecked` also available.

### Paths

The following paths are supported:

* `IntType::BITS`, `IntType::MIN` and `IntType::MAX` where `IntType` is an integer type.
* Paths to user-defined constants, functions and structs, as long as they are inside the `#[encrypted]` area. Both `super::` paths and `crate::` paths (when `assert_current_module!` is declared) are supported.
* `std::mem::replace` and `std::mem::swap`
* `Box::leak`, `Box::new`, `Cell::new`, `Cell::from_mut`

### Code organization with modules

Arcis supports nested modules, `super::` parent references, `crate::` absolute paths, and multi-file projects. `#[instruction]` functions can be placed at any module depth, not just at the top level.

**Submodules with `super::` and `crate::` paths:**

```rust theme={null}
use arcis::*;

#[encrypted]
mod my_mxe {
    use arcis::*;
    assert_current_module!(crate::my_mxe);

    const THRESHOLD: u64 = 1000;

    // No assert_current_module! needed: this module only uses super::, not crate::
    mod validation {
        use arcis::*;

        pub fn is_above_threshold(val: u64) -> bool {
            val > super::THRESHOLD  // Access parent constant via super::
        }
    }

    mod processing {
        use arcis::*;
        assert_current_module!(crate::my_mxe::processing);

        // #[instruction] works in nested modules
        #[instruction]
        pub fn process(vals: [u64; 3]) -> [u64; 3] {
            let mut result = [0u64; 3];
            for i in 0..3 {
                // Use crate:: to reference a sibling module's function
                let valid = crate::my_mxe::validation::is_above_threshold(vals[i]);
                result[i] = if valid { vals[i] * 2 } else { vals[i] };
            }
            result
        }
    }
}
```

**Multi-file projects with `encrypted_mod!`:**

```rust theme={null}
// encrypted-ixs/src/lib.rs
use arcis::*;

#[encrypted]
mod my_mxe {
    use arcis::*;

    encrypted_mod!("helpers.rs");

    type Config = helpers::Config;

    #[instruction]
    fn compute(cfg: Config) -> u64 {
        cfg.value * helpers::MULTIPLIER
    }
}
```

```rust theme={null}
// encrypted-ixs/src/helpers.rs
use arcis::*;

#[encrypted_library]
mod arcis_library {
    pub const MULTIPLIER: u64 = 42;

    pub struct Config {
        pub value: u64,
    }
}
```

<Note>
  Each file imported via `encrypted_mod!` must use `#[encrypted_library]` (not `#[encrypted]`). Items are accessible through the filename stem as a namespace (e.g., `helpers::Config`), or you can provide an alias: `encrypted_mod!("helpers.rs", utils)` makes items accessible as `utils::Config`.
</Note>

## Item support

| Item Name | Example | Support | Comments |
| - | - | - | - |
| Constant | `const MAX: u16 = 65535` | Supported | |
| Enum | `enum MyEnum { ... }` | Partial Support | Explicit discriminants are not supported. Cannot be a circuit input or output. |
| Extern | `extern ...` | Unsupported | |
| Functions | `fn foo() -> u8 { 0 }` | Partial Support | Recursive functions are not supported. |
| Impls | `impl MyType { ... }` | Supported | Generics and custom traits are supported. `MyType` must not be a reference. |
| Macro Definitions | `macro_rules! ...` | Unsupported | |
| Macro Invocations | `println!(...)` | Partial Support | [See table above](#macros) for supported macros. |
| Modules | `mod my_module { ... }` | Supported | |
| Statics | `static ...` | Unsupported | |
| Structs | `struct MyStruct { ... }` | Supported | |
| Traits | `trait MyTrait { ... }` | Partial Support | Custom traits with associated types and constants. Standard library traits forbidden.¹ |
| Type Aliases | `type MyId = usize;` | Supported | |
| Union | `union MyUnion { ... }` | Unsupported | |
| Use | `use arcis::*` | Partial Support | Only `use arcis::*` is supported. |
| Arcis Circuit | `#[arcis_circuit = "name"]` | Supported | Use a pre-built optimized circuit by name. For internal/advanced use. |

<Note>
  ¹ **Forbidden trait implementations**: You cannot manually implement `Drop`, `Deref`, `AsRef`, `AsMut`, `From`, `Into`, `TryFrom`, `TryInto`, `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Clone`, `ToOwned`, `ToString`, `Iterator`, `IntoIterator`, `DoubleEndedIterator`, `ExactSizeIterator`, `Extend`, `FromIterator`, `Fn`, `FnMut`, `FnOnce`, `Future`, `IntoFuture`, `AsyncFn`, `AsyncFnMut`, or `AsyncFnOnce`.

  **Why?** These traits have special runtime semantics (drop ordering, lazy evaluation, dynamic dispatch) that cannot be correctly translated to fixed MPC circuits. The Arcis compiler provides built-in implementations that work within MPC constraints.

  Use `#[derive(...)]` for `Clone`, `PartialEq`, `Default`, etc., which generates MPC-compatible implementations. `Default` also supports a manual `impl Default for T`.
</Note>

## Pattern support

The following patterns are supported in function arguments, `let` statements, `if let` conditions, `matches!` calls, and `match` expressions:

* simple idents: `let ident = ...;`
* mutable idents: `let mut ident = ...;`
* ref idents: `let ref ident = ...;`
* mutable ref idents: `let ref mut ident = ...;`
* parentheses around a supported pattern: `let (...) = ...;`
* reference of a supported pattern: `let &... = ...;`
* array of supported patterns: `let [...] = ...;`
* struct of supported patterns: `let MyStruct { ... } = ...;`
* tuple of supported patterns: `let (...) = ...;`
* tuple struct of supported patterns: `let MyStruct(...) = ...;`
* type pattern of a supported pattern: `let ...: ty = ...;`
* wild pattern: `let _ = ...;`

`|` patterns are supported only in `if let`, `matches!`, and `match`; they cannot be used on a `match` arm that also has a guard. The `..` pattern is only supported inside struct patterns with named fields, e.g. `MyStruct { x: 0, .. }`.

Literal, range, and path-constant patterns are only supported in `if let`, `matches!`, and `match`. Path constants must use a path such as `module::MY_CONST`; bare const identifiers are not supported as patterns.

## Pattern matching

Arcis supports `match` expressions, `if let` (including let chains), and the `matches!` macro for branching on patterns. Patterns can be literals, ranges, path constants like `module::MY_CONST`, OR-patterns, tuples, structs (with `..` rest), arrays/slices, references, bindings, and wildcards. Match arms can use `if`-guards, except an arm cannot combine a guard with an OR-pattern.

<Note>
  `let ... else` remains unsupported. In `match`, guards are supported, but an arm cannot combine a guard with an OR-pattern.
</Note>

### `match` expressions

```rust theme={null}
#[encrypted]
mod circuits {
    use arcis::*;

    pub struct Point { x: i16, y: i16 }

    #[instruction]
    pub fn classify(p: Point) -> i16 {
        match p {
            Point { x: 0, y: 0 } => 0,
            Point { x: 0, y }    => y,
            Point { x, y: 0 }    => x * 10,
            Point { x, y }       => x + y,
        }
    }

    #[instruction]
    pub fn bucket(x: u8) -> u8 {
        match x {
            v if v < 5  => 0,
            v if v < 10 => 1,
            _           => 2,
        }
    }
}
```

### `if let` and let chains

```rust theme={null}
if let Point { x: 0, y } = p {
    y
} else {
    -1
}

// let chain: bind in the first condition, use in the second
if let (0, val) = (a, b) && val < 10 {
    1
} else {
    0
}
```

<Note>
  Let chains (`if let ... && let ... && ...`) require Rust edition 2024. The default `arcium init` scaffold sets `edition = "2021"` in `encrypted-ixs/Cargo.toml`. Bump it to `edition = "2024"` to use this syntax.
</Note>

### `matches!` macro

`matches!` returns a `bool` and supports the same pattern surface:

```rust theme={null}
let in_range  = matches!(x, 0..=9);
let is_origin = matches!(p, Point { x: 0, y: 0 });

let is_short  = matches!(arr.as_slice(), [] | [_]);
```

### Slice patterns

Fixed-size arrays viewed as slices can be matched with arms of different lengths:

```rust theme={null}
match arr.as_slice() {
    []          => 0,
    [x]         => *x + 1,
    [x, y]      => *x + *y + 2,
    [_, _, _]   => 3,
    _           => 99,
}
```

<Note>
  Item shadowing of a `let` binding is rejected. Defining `fn f()` or `const F: _` after `let f = ...` (or `let F = ...`) errors at compile time with *"Cannot have an item with the same name as a variable in scope."* `let` shadowing another `let` is still allowed.
</Note>

## Generics

Arcis supports Rust generics with some constraints. Generic types must be known at compile time. Runtime polymorphism is not supported.

### Generic functions

```rust theme={null}
#[encrypted]
mod generics_example {
    use arcis::*;

    // Use a pre-built optimized circuit by name
    // The empty function body is intentional - the circuit implementation is built-in
    #[arcis_circuit = "zero"]
    fn make_zero<T: ArcisType>(a: T) -> T {}

    fn set_zero<T: ArcisType + Copy>(a: &mut T) {
        *a = make_zero(*a);
    }

    #[instruction]
    fn zero_any_type(mut arr: [u8; 10], mut val: u64) -> ([u8; 10], u64) {
        set_zero(&mut arr);
        set_zero::<u64>(&mut val);  // Turbofish syntax works
        (arr, val)
    }
}
```

### Generic structs

```rust theme={null}
struct Wrapper<T>(T);

impl<T> Wrapper<T> {
    fn new(value: T) -> Self {
        Wrapper(value)
    }

    fn into_inner(self) -> T {
        self.0
    }
}

#[instruction]
fn use_generic_struct(a: u8) -> u8 {
    Wrapper::new(a).into_inner()
}
```

### Custom traits

```rust theme={null}
trait Processable {
    type Output;
    fn process(&self) -> Self::Output;
}

impl Processable for u8 {
    type Output = u16;
    fn process(&self) -> u16 {
        *self as u16 * 2
    }
}

fn apply_process<T: Processable>(val: &T) -> T::Output {
    val.process()
}

#[instruction]
fn trait_example(x: u8) -> u16 {
    apply_process(&x)
}
```

### Generic constraints

| Feature | Supported | Notes |
| - | - | - |
| Type parameters `<T>` | Yes | Must be known at compile time |
| Trait bounds `T: Trait` | Yes | Including `ArcisType` |
| Associated types | Yes | `type Output;` |
| Associated constants | Yes | `const SIZE: usize;` |
| Where clauses | Yes | `where T: Clone` |
| Turbofish `::<T>` | Yes | For explicit type specification |
| Runtime polymorphism | No | No `dyn Trait` or trait objects |

## Iterators

Most iterator methods work in Arcis, with the notable exception of `.filter()`.

### Supported iterator methods

```rust theme={null}
#[instruction]
fn iterator_examples(arr: [u8; 10]) -> u16 {
    // Basic iteration
    let mut sum = 0u16;
    for val in arr.iter() {
        sum += *val as u16;
    }

    // Method chaining
    arr.iter()
       .map(|x| *x as u16)
       .map(|x| x * 2)
       .sum()
}
```

### Complete iterator support

| Method | Supported | Notes |
| - | - | - |
| `.iter()` | Yes | Creates iterator of references |
| `.iter_mut()` | Yes | Mutable references |
| `.into_iter()` | Yes | Consumes collection |
| `.map(f)` | Yes | Transform elements |
| `.enumerate()` | Yes | Add indices |
| `.zip(other)` | Yes | Pair with another iterator |
| `.chain(other)` | Yes | Concatenate iterators |
| `.rev()` | Yes | Reverse order |
| `.cloned()` | Yes | Clone elements |
| `.copied()` | Yes | Copy elements |
| `.fold(init, f)` | Yes | Reduce with accumulator |
| `.sum()` | Yes | Sum all elements |
| `.product()` | Yes | Multiply all elements |
| `.count()` | Yes | Count elements |
| `.take(n)` | Yes | n must be compile-time known |
| `.skip(n)` | Yes | n must be compile-time known |
| `.step_by(n)` | Yes | n must be compile-time known |
| `.for_each(f)` | Yes | Apply function to each |
| `.collect::<Box<[_]>>()` | Yes | Collect into `Box<[_]>` |
| `.next()` | Yes | Returns `Option` |
| `.nth(n)` | Yes | Returns `Option`; n must be compile-time known |
| `.last()` | Yes | Returns `Option` |
| `.reduce(f)` | Yes | Returns `Option` |
| `.max()` | Yes | Returns `Option` |
| `.min()` | Yes | Returns `Option` |
| `.max_by_key(f)` | Yes | Returns `Option` |
| `.min_by_key(f)` | Yes | Returns `Option` |
| `.filter(f)` | **No** | Would produce variable-length output |
| `.find(f)` | **No** | Would require early exit |
| `.any(f)` | **No** | Would require early exit |
| `.all(f)` | **No** | Would require early exit |

### Filter alternative

Since `.filter()` is not supported (it produces variable-length output), use a manual loop with conditionals:

```rust theme={null}
// ✗ Not supported
arr.iter().filter(|x| **x > threshold).sum()

// ✓ Manual filter pattern
#[instruction]
fn filter_sum(arr: [u8; 10], threshold: u8) -> u16 {
    let mut sum = 0u16;
    for val in arr.iter() {
        if *val > threshold {
            sum += *val as u16;
        }
    }
    sum
}
```

This pattern checks all elements but only accumulates those meeting the condition: same result, fixed execution structure.

## What's next?

<CardGroup cols={2}>
  <Card title="Primitives" icon="cube" href="/developers/arcis/primitives">
    RNG, cryptography, and data packing operations.
  </Card>

  <Card title="Best practices" icon="wand-magic-sparkles" href="/developers/arcis/best-practices">
    Performance tips, debugging, and testing strategies.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.