Skip to main content

Functions

Functions in Oxide are declared using the fn keyword with a clean, readable syntax.

Basic Syntax

fn add(a: Int, b: Int): Int {
return a + b
}

fn greet(name: String) {
println!("Hello, $name!")
}

Transpiles to:

fn add(a: isize, b: isize) -> isize {
return a + b;
}

fn greet(name: &String) {
println!("Hello, {}!", name);
}

Implicit Returns

Like Rust, Oxide supports implicit returns: the last expression in a function body (without a semicolon) is automatically returned:

// Implicit return in block body
fn double(x: Int): Int {
x * 2
}

// Implicit return with control flow
fn max(a: Int, b: Int): Int {
if a > b {
a
} else {
b
}
}

// Explicit return also works
fn early_return(x: Int): Int {
if x < 0 {
return 0
}
x * 2
}

Named Arguments

Call functions with named arguments for clarity:

fn createUser(name: String, age: Int, active: Bool): User {
return User(name, age, active)
}

// Call with named arguments
let user = createUser(name = "Alice", age = 30, active = true)

Default Arguments

Provide default values for optional parameters:

fn connect(host: String, port: Int = 8080, secure: Bool = false) {
// ...
}

connect("localhost") // Uses defaults
connect("api.example.com", port = 443, secure = true)

Transpiles to:

fn connect(host: &str, port: isize, secure: bool) {
// ...
}
// Calls are expanded with default values

Generic Functions

Place generic parameters before the function name (Kotlin-style):

fn <T> identity(x: T): T { x }

fn <T: Clone> duplicate(x: T): (T, T) { (x.clone(), x) }

fn <T, U> transform(x: T): U where T: Clone, U: From<T> {
U::from(x.clone())
}

Transpiles to:

fn identity<T>(x: T) -> T { x }

fn duplicate<T: Clone>(x: T) -> (T, T) { (x.clone(), x) }

fn transform<T, U>(x: T) -> U where T: Clone, U: From<T> {
U::from(x.clone())
}

Async Functions

Mark functions as async for asynchronous execution:

async fn fetchData(url: String): String {
let response = await http::get(url)
return response.text()
}

async fn loadAll() {
let data = await fetchData("https://api.example.com")
println!("Got: $data")
}

Transpiles to:

async fn fetch_data(url: String) -> String {
let response = http::get(url).await;
return response.text();
}

async fn load_all() {
let data = fetch_data("https://api.example.com").await;
println!("Got: {}", data);
}

See Async for comprehensive async/await documentation.

Const Functions

Use const fn for compile-time evaluable functions:

const fn square(n: Int): Int { n * n }

const fn max(a: Int, b: Int): Int { if a > b { a } else { b } }

const SIZE: Int = square(10) // Evaluated at compile time

Transpiles to:

const fn square(n: isize) -> isize { n * n }

const fn max(a: isize, b: isize) -> isize { if a > b { a } else { b } }

const SIZE: isize = square(10);

Unsafe Functions

Mark functions that perform unsafe operations:

unsafe fn dangerousOperation(ptr: *const Int): Int {
return *ptr
}

fn main() {
let value = 42
let result = unsafe {
dangerousOperation(&value as *const Int)
}
}

Transpiles to:

unsafe fn dangerous_operation(ptr: *const isize) -> isize {
return *ptr;
}

fn main() {
let value = 42;
let result = unsafe {
dangerous_operation(&value as *const isize)
};
}

Error-Throwing Functions

Use throws to indicate a function can return an error:

fn parseNumber(s: String) throws: Int {
if s.isEmpty() {
throw "Empty string"
}
return s.parse().unwrap()
}

Transpiles to:

fn parse_number(s: &str) -> Result<isize, Box<dyn std::error::Error>> {
if s.is_empty() {
return Err("Empty string".into());
}
return Ok(s.parse().unwrap());
}

See Error Handling for more on throws, try, and do-catch.

Visibility

Control function visibility with modifiers:

public fn publicApi(): String { "visible everywhere" }

internal fn crateOnly(): String { "visible in this crate" }

protected fn parentOnly(): String { "visible to parent module" }

private fn moduleOnly(): String { "visible in this module" }

Transpiles to:

pub fn public_api() -> String { "visible everywhere".to_string() }

pub(crate) fn crate_only() -> String { "visible in this crate".to_string() }

pub(super) fn parent_only() -> String { "visible to parent module".to_string() }

fn module_only() -> String { "visible in this module".to_string() }

Combined Modifiers

Modifiers can be combined:

public async fn fetchPublic(): Data { ... }

async unsafe fn unsafeAsync(): Int { ... }

public const fn publicConst(): Int { 42 }

See Also