Functions & Closures
Function Declaration
Section titled “Function Declaration”Functions in Chuks are declared with the function keyword and support type annotations:
function add(a: int, b: int): int { return a + b}
println(add(3, 4)) // 7Return Types
Section titled “Return Types”Return types are specified after the parameter list with a colon:
function greet(name: string): string { return `Hello, ${name}!`;}
function doWork(): void { println("Working...");}Optional Parameters
Section titled “Optional Parameters”Parameters can have default values, making them optional:
function createUser(name: string, age: int = 25): void { println(name + " is " + age + " years old");}
createUser("Alice"); // Alice is 25 years oldcreateUser("Bob", 30); // Bob is 30 years oldClosures (Lambdas)
Section titled “Closures (Lambdas)”Closures are anonymous functions defined inline. They capture variables from their enclosing scope:
// Lambda syntaxconst double = (x: int): int => x * 2;println(double(5)); // 10
// Multi-line closureconst process = (items: []int): []int => { var result: []int = []; for (item of items) { result.push(item * 2); } return result;}Higher-Order Functions
Section titled “Higher-Order Functions”Functions can accept other functions as arguments and return functions:
function apply(fn: (int) => int, val: int): int { return fn(val);}
function multiplier(factor: int): (int) => int { return (x: int): int => x * factor;}
const triple = multiplier(3);println(apply(triple, 10)); // 30Function Types with Named Parameters
Section titled “Function Types with Named Parameters”When declaring function type annotations, you can include parameter names for clarity. The syntax is function(name: type, ...): returnType.
// Function type with named parametersvar greet: function(name: string): string = function(name: string): string { return "Hello, " + name;}println(greet("World")); // Hello, WorldNamed parameters make callback signatures easier to read:
// Named params in callback typefunction applyOp(a: int, b: int, op: function(x: int, y: int): int): int { return op(a, b);}
var sum = applyOp(10, 5, function(x: int, y: int): int { return x + y;});println(sum); // 15Function types without names (positional) are also supported:
var double: function(int): int = function(n: int): int { return n * 2;}println(double(21)); // 42Return function types with named parameters for self-documenting code:
function makeAdder(n: int): function(x: int): int { return function(x: int): int { return x + n; }}
var add5: any = makeAdder(5);println(add5(10)); // 15Nullable Function Types
Section titled “Nullable Function Types”A function-typed variable or field can be made nullable with the function? syntax. This declares that the value is either a callable function or null.
Basic Usage
Section titled “Basic Usage”var handler: function?(msg: string): void = null
if (handler == null) { println("no handler set")}
handler = function(msg: string): void { println("received: " + msg)}handler("hello") // received: helloThe ? goes directly after the function keyword — not after the return type. This makes it clear that the function itself is nullable, not the return value.
As Method Parameters
Section titled “As Method Parameters”Nullable function types are useful for optional callbacks:
function runCallback(cb: function?(): void): void { if (cb != null) { cb() } else { println("no callback") }}
runCallback(null) // no callbackrunCallback(function(): void { println("ran") }) // ranIn Classes
Section titled “In Classes”Classes can store nullable function fields for event handlers, hooks, and configurable behavior:
class EventEmitter { private var onMessageHandler: function?(msg: string): void = null private var onCloseHandler: function?(): void = null
public onMessage(h: function?(msg: string): void): void { this.onMessageHandler = h }
public onClose(h: function?(): void): void { this.onCloseHandler = h }
public emit(msg: string): void { if (this.onMessageHandler != null) { this.onMessageHandler(msg) } }
public close(): void { if (this.onCloseHandler != null) { this.onCloseHandler() } }}
var emitter = new EventEmitter()emitter.onMessage(function(msg: string): void { println("msg: " + msg)})emitter.emit("hello") // msg: hello
// Reset handler to nullemitter.onMessage(null)With Return Types
Section titled “With Return Types”Nullable functions can have any return type, including nullable return types:
// Nullable function that returns intvar transform: function?(x: int): int = nulltransform = function(x: int): int { return x * 2}println(transform(21)) // 42
// Nullable function that returns int?var lookup: function?(key: string): int? = nulllookup = function(key: string): int? { if (key == "age") { return 25 } return null}With Generics
Section titled “With Generics”Nullable function types work with generic type parameters:
class Processor<T> { private var handler: function?(msg: T): void = null
public setHandler(h: function?(msg: T): void): void { this.handler = h }
public process(data: T): void { if (this.handler != null) { this.handler(data) } else { println("no handler") } }}
var p = new Processor<string>()p.process("test") // no handlerp.setHandler(function(msg: string): void { println("got: " + msg)})p.process("test") // got: testAsync Functions
Section titled “Async Functions”Functions that perform asynchronous work are declared with async and return a Task<T>:
async function fetchData(url: string): Task<string> { const resp = await http.get(url); return resp.body;}See the Concurrency guide for details on async/await and spawn.