Built-in Functions
Built-in Functions
Section titled “Built-in Functions”Ferret provides several built-in functions that are available in every module without needing to import them. These functions help you work with arrays, maps, and perform common operations.
Container Operations
Section titled “Container Operations”Ferret provides a unified set of built-in functions that work with both arrays and maps. These functions respect Ferret’s borrow semantics: read operations use immutable references (&T), while write operations require mutable references (&mut T).
len(value) -> i32
Section titled “len(value) -> i32”Returns the length of a string, array, or map.
let s: str = "Hello";let arr: []i32 = [1, 2, 3];let scores := {"alice" => 95, "bob" => 87} as map[str]i32;
let str_len := len(s); // 5let arr_len := len(arr); // 3let map_size := len(scores); // 2get(&container, key) -> T?
Section titled “get(&container, key) -> T?”Safely retrieves a value from an array or map, returning an optional type. Returns none if the key/index doesn’t exist.
let arr: []i32 = [10, 20, 30];let scores := {"alice" => 95, "bob" => 87} as map[str]i32;
// Array accesslet val1 := get(&arr, 0); // Returns i32? with value 10let val2 := get(&arr, 10); // Returns i32? with value none (out of bounds)
// Map accesslet score1 := get(&scores, "alice"); // Returns i32? with value 95let score2 := get(&scores, "charlie"); // Returns i32? with value none (key doesn't exist)Note: get() uses an immutable reference (&T) since it only reads from the container.
get_or(&container, key, fallback) -> T
Section titled “get_or(&container, key, fallback) -> T”Retrieves a value from an array or map, returning the fallback value if the key/index doesn’t exist.
let arr: []i32 = [10, 20, 30];let scores := {"alice" => 95} as map[str]i32;
// Array access with fallbacklet val1 := get_or(&arr, 1, 999); // 20let val2 := get_or(&arr, 10, 999); // 999 (fallback)
// Map access with fallbacklet score1 := get_or(&scores, "alice", 0); // 95let score2 := get_or(&scores, "bob", 0); // 0 (fallback)This is a convenient alternative to using the coalescing operator with get().
has(&container, key) -> bool
Section titled “has(&container, key) -> bool”Checks if a key or index exists in an array or map.
let arr: []i32 = [10, 20, 30];let scores := {"alice" => 95, "bob" => 87} as map[str]i32;
// Array bounds checkinglet has_index := has(&arr, 0); // truelet out_of_bounds := has(&arr, 10); // false
// Map key checkinglet has_alice := has(&scores, "alice"); // truelet has_charlie := has(&scores, "charlie"); // falseset(&mut container, key, value) -> bool
Section titled “set(&mut container, key, value) -> bool”Sets a value in an array or map. Returns true on success, false if the operation fails (e.g., out of bounds for arrays).
let arr: []i32 = [10, 20, 30];let scores := {"alice" => 95} as map[str]i32;
// Array modification (requires mutable reference)set(&mut arr, 0, 100);io::Println(arr[0]); // 100
// Map modification (requires mutable reference)set(&mut scores, "bob", 87); // Adds new keyset(&mut scores, "alice", 96); // Updates existing keyImportant: set() requires a mutable reference (&mut T) because it modifies the container.
remove(&mut container, key) -> bool
Section titled “remove(&mut container, key) -> bool”Removes a key from a map. Returns true if the key was found and removed, false otherwise.
let scores := {"alice" => 95, "bob" => 87} as map[str]i32;
// Remove a key (requires mutable reference)let removed := remove(&mut scores, "bob"); // truelet not_found := remove(&mut scores, "charlie"); // false
// Check if key still existslet has_bob := has(&scores, "bob"); // falseNote: remove() only works with maps, not arrays. Arrays don’t support removing elements (use slices or create a new array).
Array-Only Operations
Section titled “Array-Only Operations”These functions work specifically with dynamic arrays.
append(&mut array, value) -> bool
Section titled “append(&mut array, value) -> bool”Appends an element to the end of a dynamic array. Returns true on success.
let arr: []i32 = [10, 20, 30];
// Append a value (requires mutable reference)append(&mut arr, 40);io::Println(len(arr)); // 4io::Println(arr[3]); // 40Note: append() only works with dynamic arrays ([]T), not fixed-size arrays ([N]T).
insert(&mut array, index, value) -> bool
Section titled “insert(&mut array, index, value) -> bool”Inserts an element at a specific index in a dynamic array, shifting existing elements. Returns true on success, false if the index is invalid.
let arr: []i32 = [10, 20, 30];
// Insert at index 1 (requires mutable reference)insert(&mut arr, 1, 15);// arr is now [10, 15, 20, 30]
io::Println(arr[1]); // 15io::Println(arr[2]); // 20 (shifted)io::Println(len(arr)); // 4Note: insert() only works with dynamic arrays. The index must be between 0 and len(array) (inclusive).
Direct Container Access
Section titled “Direct Container Access”Array Indexing
Section titled “Array Indexing”Direct array indexing arr[index] returns the value type T directly. For fixed-size arrays with constant indices, Ferret performs compile-time bounds checking:
let arr: [5]i32 = [1, 2, 3, 4, 5];
let x := arr[2]; // ✅ OK - returns i32let y := arr[10]; // ❌ Compile error: constant index 10 is out of bounds!
// Runtime indices panic if out of boundslet i := 10;let z := arr[i]; // ❌ Runtime panic: index out of bounds!For safe access without panics, use get(), get_or(), or has() instead.
Map Indexing
Section titled “Map Indexing”Direct map indexing map[key] returns the value type T directly (not T?). If the key doesn’t exist, the program will panic:
let scores := {"alice" => 95, "bob" => 87} as map[str]i32;
let alice_score := scores["alice"]; // ✅ 95 (returns i32)let bob_score := scores["bob"]; // ✅ 87 (returns i32)let charlie_score := scores["charlie"]; // ❌ Panic: key not found!Important: Use get() or get_or() if you’re unsure whether a key exists. Direct indexing should only be used when you’re certain the key exists.
Borrow Semantics
Section titled “Borrow Semantics”All built-in functions respect Ferret’s borrow semantics:
- Read operations (
get,get_or,has) use immutable references (&T) - Write operations (
set,remove,append,insert) require mutable references (&mut T)
let arr: []i32 = [10, 20, 30];
// ✅ OK - read operations with immutable referencelet val := get(&arr, 0);let exists := has(&arr, 1);
// ✅ OK - write operations with mutable referenceset(&mut arr, 0, 100);append(&mut arr, 40);
// ❌ Error - can't use immutable reference for mutationset(&arr, 0, 100); // Compile error: requires mutable referenceBest Practices
Section titled “Best Practices”Use get() for Safe Access
Section titled “Use get() for Safe Access”When you’re not sure if a key/index exists, use get():
let scores := {"alice" => 95} as map[str]i32;
// ✅ Safe - handles missing keyslet score := get(&scores, "bob");if score != none { process(score);}Use get_or() for Defaults
Section titled “Use get_or() for Defaults”When you have a sensible default value, use get_or():
let scores := {"alice" => 95} as map[str]i32;
// ✅ Convenient - provides default in one linelet score := get_or(&scores, "bob", 0);Use Direct Indexing When Certain
Section titled “Use Direct Indexing When Certain”Only use direct indexing when you’re certain the key/index exists:
let arr: []i32 = [10, 20, 30];
// ✅ Safe - we know index 0 existslet first := arr[0];
// ❌ Dangerous - might paniclet unknown := arr[100];Check Before Mutating
Section titled “Check Before Mutating”Use has() to check before performing operations:
let scores := {"alice" => 95} as map[str]i32;
if has(&scores, "bob") { set(&mut scores, "bob", 87);} else { // Handle missing key}Summary
Section titled “Summary”Ferret’s built-in functions provide a safe and consistent way to work with containers:
len()- Get the length/size of strings, arrays, and mapsget(&c, k) -> T?- Safe access returning optionalget_or(&c, k, fallback) -> T- Access with default valuehas(&c, k) -> bool- Check if key/index existsset(&mut c, k, v) -> bool- Set value (requires mutable reference)remove(&mut c, k) -> bool- Remove key from map (requires mutable reference)append(&mut a, v) -> bool- Append to array (requires mutable reference)insert(&mut a, i, v) -> bool- Insert into array (requires mutable reference)
All functions respect Ferret’s borrow semantics, ensuring memory safety and preventing data races.