Functions

Function types, signatures, and calling


Declaration

Declaring functions is like declaring variables, but the function body must be defined at declaration time. Functions can be defined as var or const, making them dynamically or statically dispatched, respectively. Since the body must be defined, the type annotation for the function is inferred and therefore optional to write. Functions inside structs can be static so that only one copy is dispatched; its host struct’s non-static members are not in scope in the body. The type declaration for a function is func<(arg types) -> return type>, where arg types are a comma-separated list. Functions can take and return functions to create higher-order functions.

Examples

// This is a function that takes two numbers and returns their product
const product = (a: f64, b: f64) -> f64 {
	return a * b;
}

// This function takes nothing and returns no value, but can be reseated at runtime
var doThing = () -> void {
	
}

// This function composes two functions into one
const compose = (f1: func<(f64, f64) -> f64>, f2: func<(f64, f64) -> f64>) -> func<(f64, f64) -> f64> {
	const pi = 3.14159;
	
	// Return a closure
	return (a: f64, b: f64) -> f64 {
		a *= pi;
		b /= pi;

		// Calling functions and using their returns inline
		return f1(a, b) ** f2(a, b);
	};
}

Closures

Closures always capture their state by value, so primitive variables are copied, and owned pointers are moved into the closure body. References can’t be captured. Returning a closure always creates a new heap allocation.


⬅️ Variables and Constants | Control Flow ➡️