Skip to content
Fe 26.0 is not production-ready. This is an initial release of a new compiler. Learn more

Fe for Rust Developers

Fe draws heavy inspiration from Rust. This guide highlights what’s familiar and what’s different for Rust developers.

Fe structs work like Rust structs:

struct Point {
x: u256,
y: u256,
}
let p = Point { x: 10, y: 20 }
let x = p.x

Methods are defined in impl blocks:

struct Counter {
value: u256,
}
impl Counter {
fn new() -> Self {
Counter { value: 0 }
}
fn increment(mut self) {
self.value += 1
}
fn get(self) -> u256 {
self.value
}
}

Traits define shared behavior:

trait Hashable {
fn hash(self) -> u256
}
impl Hashable for Point {
fn hash(self) -> u256 {
self.x ^ self.y
}
}

Type parameters work similarly:

fn identity<T>(value: own T) -> T {
value
}
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(own self) -> T {
self.value
}
}

Constrain generics with trait bounds:

fn process<T: Hashable>(item: T) -> u256 {
item.hash()
}
fn complex<T: Hashable + Printable>(item: T) {
// T must implement both traits
}

Enums with match expressions:

enum Status {
Pending,
Active,
Completed { result: u256 },
}
fn handle(status: Status) -> u256 {
match status {
Status::Pending => 0,
Status::Active => 1,
Status::Completed { result } => result,
}
}

Optional values use Option<T>:

let maybe: Option<u256> = Option::Some(42)
match maybe {
Option::Some(v) => v,
Option::None => 0,
}

Most constructs are expressions:

let value: u256 = if condition { 10 } else { 20 }
let result = match status {
Status::Active => true,
_ => false,
}

Types are inferred where possible:

let x = true // Type inferred as bool
let y: u8 = 42 // Explicit annotation

Variables are immutable by default:

let x: u256 = 10 // Immutable
let mut y: u256 = 10 // Mutable
y = 20 // OK

Fe has ownership concepts similar to Rust (own, ref, mut) but with key differences:

  • Default is view mode (no keyword): the function can read the value but not move or modify it. Unlike Rust, view-mode parameters can be used multiple times without explicit borrowing:
fn process(data: MyStruct) {
// View mode: read-only access, no ownership transfer
}
let a = MyStruct { x: 1 }
process(data: a)
process(data: a) // Fine: view mode doesn't consume the value
  • own transfers ownership (like Rust’s move): the caller cannot use the value after passing it
  • ref creates a read-only reference that can be stored in struct fields (like Rust’s &T)
  • mut creates a mutable handle (like Rust’s &mut T)

Fe also has a borrow checker that prevents simultaneous ref and mut access to the same data.

Fe does not require lifetime annotations. References are scoped but the compiler manages lifetimes implicitly.

See Ownership & Mutability for details on own, ref, and mut.

Currently, Fe has basic loop constructs but not yet the full iterator pattern:

// Rust: items.iter().map(|x| x + 1).collect()
// Fe: Currently uses manual while loops
let mut i: u256 = 0
while i < len {
// process items[i]
i = i + 1
}

Fe doesn’t support closures:

// Rust: let add = |a, b| a + b;
// Fe: Use named functions
fn add(a: u256, b: u256) -> u256 {
a + b
}

Fe has modules, but uses different terminology:

| Rust | Fe |

Fe has modules, but uses different terminology:

RustFe
CrateIngot
ModuleModule
// In fe.toml
[dependencies]
my_lib = { path = "../my_lib" }

Fe organizes code into ingots (packages) containing modules, similar to Rust’s crate/module system.

Fe has first-class contract support:

contract Token {
store: TokenStorage
init(supply: u256) uses (mut store) {
}
recv TokenMsg {
}
}

External interfaces are defined separately:

use std::abi::sol
msg TokenMsg {
#[selector = sol("transfer(address,uint256)")]
Transfer { to: Address, amount: u256 } -> bool,
}

Persistent key-value storage:

struct Storage {
balances: StorageMap<Address, u256>,
}

Blockchain events for logging:

#[event]
struct Transfer {
#[indexed]
from: Address,
#[indexed]
to: Address,
value: u256,
}

Explicit capability tracking:

fn transfer(from: Address, to: Address, amount: u256)
uses (store: mut TokenStore, log: mut Log)
{
// Function declares what it accesses
}
ConceptRustFe
Functionfn foo() {}fn foo() {}
Structstruct Foo {}struct Foo {}
Implimpl Foo {}impl Foo {}
Traittrait Bar {}trait Bar {}
Genericsfn foo<T>()fn foo<T>()
BoundsT: TraitT: Trait
Matchmatch x {}match x {}
Ifif x {}if x {}
Looploop {}loop {}
Forfor x in iter {}for x in iter {}
Letlet x = 1;let x = 1
Mutlet mut x = 1;let mut x = 1
Returnreturn xreturn x
Selfselfself
Self typeSelfSelf
FeatureStatus in Fe
Ownership/BorrowingNot applicable (effects instead)
LifetimesNot needed
ClosuresNot available
IteratorsPlanned (trait-based)
async/awaitNot applicable
MacrosNot available
FeatureDescription
contractSmart contract declarations
msgMessage type definitions
recvMessage handlers
initContract constructors
usesEffect declarations
withEffect binding
#[selector]ABI selector attributes
#[indexed]Event indexing
Map<K, V>Storage mappings