Standard Traits
Fe provides several built-in traits that enable core language functionality. Understanding these helps you work effectively with Fe’s type system.
MsgVariant
Section titled “MsgVariant”The MsgVariant trait is automatically implemented for message variants. It provides the selector and return type information needed for ABI compatibility.
trait MsgVariant { const SELECTOR: u32 type Return}When you define a message:
msg TokenMsg { #[selector = 0xa9059cbb] Transfer { to: u256, amount: u256 } -> bool,}The compiler generates an implementation like:
// Conceptually generated by the compilerimpl MsgVariant for TokenMsg_Transfer { const SELECTOR: u32 = 0xa9059cbb type Return = bool}This trait enables:
- Type-safe message routing
- Compile-time selector verification
- Generic code over message types
Numeric Traits
Section titled “Numeric Traits”Fe provides traits for numeric operations:
Arithmetic
Section titled “Arithmetic”trait Add { fn add(self, other: Self) -> Self}
trait Sub { fn sub(self, other: Self) -> Self}
trait Mul { fn mul(self, other: Self) -> Self}
trait Div { fn div(self, other: Self) -> Self}Primitive numeric types implement these automatically.
Comparison
Section titled “Comparison”trait Eq { fn eq(self, other: Self) -> bool}
trait Ord { fn lt(self, other: Self) -> bool fn le(self, other: Self) -> bool fn gt(self, other: Self) -> bool fn ge(self, other: Self) -> bool}Common Trait Patterns
Section titled “Common Trait Patterns”While Fe may not have all these as built-ins yet, these patterns are commonly defined:
Default
Section titled “Default”Provides a default value:
trait Default { fn default() -> Self}
struct Counter { value: u256,}
impl Default for Counter { fn default() -> Self { Counter { value: 0 } }}
let c = Counter::default()Creates a copy of a value:
trait Clone { fn clone(self) -> Self}
struct Point { x: u256, y: u256,}
impl Clone for Point { fn clone(self) -> Self { Point { x: self.x, y: self.y } }}Into/From
Section titled “Into/From”Converts between types:
trait Into<T> { fn into(self) -> T}
trait From<T> { fn from(value: T) -> Self}
struct Percentage { basis_points: u256,}
impl From<u256> for Percentage { fn from(value: u256) -> Self { Percentage { basis_points: value } }}Defining Your Own Standard Traits
Section titled “Defining Your Own Standard Traits”For your projects, define common traits that types should implement:
Identifiable
Section titled “Identifiable”trait Identifiable { fn id(self) -> u256}
struct User { user_id: u256, name: String,}
impl Identifiable for User { fn id(self) -> u256 { self.user_id }}
struct Token { token_id: u256, value: u256,}
impl Identifiable for Token { fn id(self) -> u256 { self.token_id }}
// Generic function works with any Identifiablefn get_id<T: Identifiable>(item: T) -> u256 { item.id()}Validatable
Section titled “Validatable”trait Validatable { fn is_valid(self) -> bool}
struct Transfer { from: u256, to: u256, amount: u256,}
impl Validatable for Transfer { fn is_valid(self) -> bool { self.from != 0 && self.to != 0 && self.amount > 0 }}
fn process<T: Validatable>(item: T) -> bool { if !item.is_valid() { return false } // ... process valid item true}Hashable
Section titled “Hashable”trait Hashable { fn hash(self) -> u256}
struct Order { id: u256, price: u256, quantity: u256,}
impl Hashable for Order { fn hash(self) -> u256 { // Simple hash combining fields self.id ^ self.price ^ self.quantity }}Using Traits for Interfaces
Section titled “Using Traits for Interfaces”Define trait “interfaces” for your contract patterns:
ERC-Style Traits
Section titled “ERC-Style Traits”trait ERC20 { fn total_supply(self) -> u256 fn balance_of(self, account: u256) -> u256 fn transfer(mut self, to: u256, amount: u256) -> bool}
trait ERC721 { fn owner_of(self, token_id: u256) -> u256 fn transfer_from(mut self, from: u256, to: u256, token_id: u256)}
trait Ownable { fn owner(self) -> u256 fn transfer_ownership(mut self, new_owner: u256)}
trait Pausable { fn paused(self) -> bool fn pause(mut self) fn unpause(mut self)}Trait Composition
Section titled “Trait Composition”Build complex behaviors from simple traits:
trait Readable { fn read(self) -> u256}
trait Writable { fn write(mut self, value: u256)}
// Require both for read-write accessfn update<T: Readable + Writable>(mut storage: T, delta: u256) { let current = storage.read() storage.write(current + delta)}Summary
Section titled “Summary”| Trait | Purpose |
|---|---|
MsgVariant | Message variant metadata (selector, return type) |
Add, Sub, Mul, Div | Arithmetic operations |
Eq, Ord | Comparison operations |
Default | Default value construction |
Clone | Value duplication |
Into, From | Type conversion |
Standard traits provide the foundation for generic, reusable code. Define your own traits to create consistent interfaces across your codebase.