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

Impl Blocks

Impl blocks let you define methods on structs. Methods are functions associated with a type that can access the struct’s data through self.

Define methods in an impl block:

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

Methods take self as their first parameter, giving access to the struct instance:

struct Point {
x: u256,
y: u256,
}
impl Point {
fn magnitude_squared(self) -> u256 {
self.x * self.x + self.y * self.y
}
}
let p = Point { x: 3, y: 4 }
let mag_sq = p.magnitude_squared() // 25

Use self for read-only access, mut self when you need to modify:

impl Counter {
// Read-only: uses self
fn get(self) -> u256 {
self.value
}
// Modifying: uses mut self
fn set(mut self, new_value: u256) {
self.value = new_value
}
// Modifying: uses mut self
fn increment(mut self) {
self.value += 1
}
}

The compiler enforces this. You can’t modify through a non-mut self:

impl Counter {
fn broken(self) {
self.value = 10 // Error: cannot mutate through immutable self
}
}

Call methods with dot notation:

let mut counter = Counter { value: 0 }
let v = counter.get() // 0
counter.increment()
let v2 = counter.get() // 1
counter.set(100)
let v3 = counter.get() // 100

Methods returning self enable chaining:

struct Builder {
width: u256,
height: u256,
depth: u256,
}
impl Builder {
fn with_width(mut self, w: u256) -> Builder {
self.width = w
self
}
fn with_height(mut self, h: u256) -> Builder {
self.height = h
self
}
fn with_depth(mut self, d: u256) -> Builder {
self.depth = d
self
}
}
let b = Builder { width: 0, height: 0, depth: 0 }
.with_width(10)
.with_height(20)
.with_depth(30)

You can split methods across multiple impl blocks:

struct Token {
balance: u256,
frozen: bool,
}
// Core functionality
impl Token {
fn get_balance(self) -> u256 {
self.balance
}
fn set_balance(mut self, amount: u256) {
self.balance = amount
}
}
// Freeze functionality
impl Token {
fn is_frozen(self) -> bool {
self.frozen
}
fn freeze(mut self) {
self.frozen = true
}
fn unfreeze(mut self) {
self.frozen = false
}
}

Methods can take parameters beyond self:

struct Wallet {
balance: u256,
}
impl Wallet {
fn deposit(mut self, amount: u256) {
self.balance += amount
}
fn withdraw(mut self, amount: u256) -> bool {
if self.balance < amount {
return false
}
self.balance -= amount
true
}
fn transfer_to(mut self, other: Wallet, amount: u256) -> bool {
if self.balance < amount {
return false
}
self.balance -= amount
// Note: other would need to be mut to receive
true
}
}

Methods can be public or private:

impl Counter {
// Public method
pub fn get(self) -> u256 {
self.value
}
// Private helper
fn validate(self) -> bool {
self.value < 1000000
}
}

Only structs can have impl blocks. Contracts cannot:

// ✓ This works - struct with impl
struct Helper {
data: u256,
}
impl Helper {
fn process(self) -> u256 {
self.data * 2
}
}
// ✗ This does NOT work - contracts cannot have impl blocks
contract Token {
store: TokenStorage,
}
impl Token { // Error: cannot implement methods on contracts
fn get_balance(self) -> u256 { ... }
}

For contracts, use standalone functions with effects instead:

fn get_balance(account: u256) -> u256 uses (store: TokenStorage) {
store.balances.get(account)
}
SyntaxDescription
impl Type { }Define methods for a type
fn method(self)Read-only method
fn method(mut self)Mutating method
instance.method()Call a method
pub fnPublic method