Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Method Calls and Field Access

Cambrian uses dot notation for both field access on records and method calls on built-in types. Bracket notation provides indexed access to maps and collections.

Field Access

Record fields are accessed with the dot operator:

let seller = listing.seller;
let is_live = listing.active;
let max = m_config.limits.max_deposit;

Member state variables are accessed by name within member transforms, where clauses, macros, and route actions:

where m_balance >= amount : throw 100

Map Access

HashMap values are accessed with bracket notation:

let bal = m_balances[account];

Bracket access never fails: a missing key yields the value type’s default (0 for numbers, false for bool, and so on), just like a Solidity mapping. A stored 0 and an absent key look the same through []; use m.exists(k) (or its alias m.contains(k)) when membership matters:

let known = m_balances.exists(account);

Method Calls

Built-in types provide methods that are called with dot notation:

Vec Methods

let size = m_items.len();
let first = m_items[0];
let empty = m_items.len() == 0;

push appends an element; it is used as the result of a member transform (in add(x) => m_items.push(x)).

HashMap Methods

let has_key = m_map.exists(key);
let also_has = m_map.contains(key);
let empty = m_map.is_empty();

Writes happen in member transforms: m.insert(k, v), m.update(k, v), and m.remove(k) each return the updated map.

Option Values

Option<T> has no accessor methods: unwrap, unwrap_or, is_some, is_none, and expect are rejected at compile time, as are .get / .set on maps and vectors (use m[k], v[i], and the member-transform writes). Take an Option apart with match:

let val = match opt {
    some(v) => v,
    none => 0
};

String Methods

let size = name.len();

len() on a String counts UTF-8 bytes, not characters.

Method Chaining

Map writes return the updated map, so they can be chained:

m_balances: HashMap<address, U256> {
    in transfer(to, amount) => m_balances
        .insert(msg::sender, m_balances[msg::sender] - amount)
        .insert(to, m_balances[to] + amount)
}

This pattern is common in member transforms where multiple map updates happen atomically.

Type Casts

The as keyword casts a value to a different type:

let wide = narrow_val as u64;
let big = amount as U256;

Widening between unsigned integer types happens automatically: in small + x with small: u8 and x: u64, small is widened to u64. An explicit as is needed to narrow, or to pin a specific width. See Type Widening and Arithmetic and Logic.

Common Cast Patterns

// Narrowing: checked -- reverts if the value does not fit
let byte_val = large_num as u8;

// Widening: always safe
let big_val = small_num as u128;

Narrowing with as does not truncate: if the value is out of range for the target type, the transaction reverts.

Combining Access Patterns

Field access, method calls, and bracket access can be combined freely:

let bidder_balance = m_auctions[auction_id].highest_bid.amount;
let last_amount = m_bids[m_bids.len() - 1].amount;

Pure Function Calls

Top-level pure functions are called by name (without dot notation):

let fee = compute_fee(amount, rate);
let clamped = clamp(value, min, max);

Macro Invocation

Entity-scoped macros are called with the @ prefix:

where @is_owner() : throw 100

Macros look like function calls but can access entity state. See Macros for details.