Functions are first-class citizens in Topaz. You can store them in variables, pass them as parameters to other functions, and return them from functions. 🚀
�� Basic Function Declaration
Standard Function Declaration
// Basic function structure
function greet(name: string) -> string {
return "Hello, {name}!"
}
// Function without parameters
function getCurrentTime() -> string {
return "December 20, 2024"
}
// Function without return value (void)
function logMessage(message: string) {
print("Log: {message}")
}
// Usage examples
let greeting = greet("Topaz Developer")
print(greeting) // "Hello, Topaz Developer!"
Parameters and Default Values
// Default parameter values
function calculate(a: int, b: int = 10, operation: string = "add") -> int {
match operation {
case "add" => return a + b
case "subtract" => return a - b
case "multiply" => return a * b
case _ => return 0
}
}
// Various calling methods
let result1 = calculate(5) // 5 + 10 = 15
let result2 = calculate(5, 3) // 5 + 3 = 8
let result3 = calculate(5, 3, "multiply") // 5 * 3 = 15
// Named parameters
let result4 = calculate(a: 8, operation: "subtract", b: 3) // 8 - 3 = 5
Variadic Parameters
// Variadic parameters (...rest)
function sum(numbers: ...int) -> int {
let mut total = 0
for number in numbers {
total += number
}
return total
}
let total1 = sum(1, 2, 3, 4, 5) // 15
let total2 = sum(10, 20) // 30
// Combining array with additional parameters
function calculateStats(label: string, values: ...float) -> string {
let count = values.length()
let average = values.sum() / count
return "{label}: count={count}, average={average}"
}
print(calculateStats("Test Scores", 85.5, 92.0, 78.5, 89.0))
➡️ Arrow Functions
Basic Arrow Functions
// Simple arrow function
let square = (x: int) => x * x
let greet = (name: string) => "Hi, {name}!"
// Arrow function without parameters
let randomNumber = () => Math.random() * 100
// Complex arrow function
let userInfo = (name: string, age: int) => {
let status = if age >= 18 { "adult" } else { "minor" }
return {
name: name,
age: age,
status: status
}
}
// Usage examples
print(square(5)) // 25
print(greet("TopazDev")) // "Hi, TopazDev!"
let info = userInfo("John", 25)
print(info) // { name: "John", age: 25, status: "adult" }
Array Methods with Arrow Functions
let numbers = [1, 2, 3, 4, 5]
// map transformation
let squares = numbers.map(x => x * x)
print(squares) // [1, 4, 9, 16, 25]
// filter filtering
let evens = numbers.filter(x => x % 2 == 0)
print(evens) // [2, 4]
// reduce reduction
let total = numbers.reduce((acc, current) => acc + current, 0)
print(total) // 15
// Complex chaining
let result = numbers
.filter(x => x > 2)
.map(x => x * 3)
.reduce((a, b) => a + b, 0)
print(result) // (3 + 4 + 5) * 3 = 36
🎯 Higher-Order Functions
Functions as Parameters
// Higher-order function definition
function applyOperation(array: [int], operation: function(int) -> int) -> [int] {
let result = []
for element in array {
result.push(operation(element))
}
return result
}
// Pass functions as parameters
let numbers = [1, 2, 3, 4]
let squareResult = applyOperation(numbers, x => x * x)
let doubleResult = applyOperation(numbers, x => x * 2)
print(squareResult) // [1, 4, 9, 16]
print(doubleResult) // [2, 4, 6, 8]
// Conditional processing function
function conditionalProcess(value: int, condition: function(int) -> bool, processor: function(int) -> int) -> int {
if condition(value) {
return processor(value)
}
return value
}
let result = conditionalProcess(15, x => x > 10, x => x * 2)
print(result) // 30 (since 15 > 10, so 15 * 2)
Returning Functions
// Function factory
function createMultiplier(factor: int) -> function(int) -> int {
return function(x: int) -> int {
return x * factor
}
}
let doubler = createMultiplier(2)
let tripler = createMultiplier(3)
print(doubler(5)) // 10
print(tripler(4)) // 12
// Configurable validator function
function createRangeValidator(min: int, max: int) -> function(int) -> bool {
return function(value: int) -> bool {
return value >= min && value <= max
}
}
let adultAgeValidator = createRangeValidator(18, 65)
let studentAgeValidator = createRangeValidator(5, 18)
print(adultAgeValidator(25)) // true
print(studentAgeValidator(16)) // true
print(studentAgeValidator(25)) // false
🔒 Closures
Basic Closures
function createCounter(initialValue: int) -> function() -> int {
let mut count = initialValue // Captured by closure
return function() -> int {
count += 1 // Access to outer variable
return count
}
}
let counter1 = createCounter(0)
let counter2 = createCounter(100)
print(counter1()) // 1
print(counter1()) // 2
print(counter2()) // 101
print(counter1()) // 3
Complex Closure Patterns
// Stateful closure
function createAccount(initialBalance: float) -> { deposit: function(float) -> float, withdraw: function(float) -> float, checkBalance: function() -> float } {
let mut balance = initialBalance
return {
deposit: function(amount: float) -> float {
balance += amount
return balance
},
withdraw: function(amount: float) -> float {
if amount <= balance {
balance -= amount
}
return balance
},
checkBalance: function() -> float {
return balance
}
}
}
let myAccount = createAccount(1000.0)
print(myAccount.deposit(500.0)) // 1500.0
print(myAccount.withdraw(200.0)) // 1300.0
print(myAccount.checkBalance()) // 1300.0
// Environment-capturing closure
function createConfigManager(defaultConfig: { [string]: any }) -> function(string, any) -> any {
let mut currentConfig = defaultConfig.copy()
return function(key: string, value: any = null) -> any {
if value != null {
currentConfig[key] = value
}
return currentConfig[key]
}
}
let appConfig = createConfigManager({
theme: "dark",
language: "English",
notifications: true
})
print(appConfig("theme")) // "dark"
appConfig("theme", "light")
print(appConfig("theme")) // "light"
🔄 Recursive Functions
Basic Recursion
// Factorial calculation
function factorial(n: int) -> int {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
print(factorial(5)) // 120
// Fibonacci sequence
function fibonacci(n: int) -> int {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
print(fibonacci(8)) // 21
// Array sum (recursive)
function arraySum(array: [int]) -> int {
if array.length() == 0 {
return 0
}
if array.length() == 1 {
return array[0]
}
return array[0] + arraySum(array.slice(1))
}
print(arraySum([1, 2, 3, 4, 5])) // 15
Tail Recursion Optimization
// Tail recursive factorial
function tailFactorial(n: int, accumulator: int = 1) -> int {
if n <= 1 {
return accumulator
}
return tailFactorial(n - 1, accumulator * n) // Tail call
}
// Tail recursive fibonacci
function tailFibonacci(n: int, a: int = 0, b: int = 1) -> int {
if n == 0 {
return a
}
return tailFibonacci(n - 1, b, a + b) // Tail call
}
print(tailFactorial(10)) // 3628800
print(tailFibonacci(10)) // 55
⚡ Functional Programming Patterns
Currying
// Curried function
function add(a: int) -> function(int) -> int {
return function(b: int) -> int {
return a + b
}
}
let addFive = add(5)
print(addFive(3)) // 8
// Multi-parameter currying
function multiplyAndAdd(multiplier: float) -> function(float) -> function(float) -> float {
return function(addend: float) -> function(float) -> float {
return function(value: float) -> float {
return value * multiplier + addend
}
}
}
let doubleAndAddTen = multiplyAndAdd(2.0)(10.0)
print(doubleAndAddTen(5.0)) // 20.0 (5 * 2 + 10)
Function Composition
// Function composition utility
function compose<T, U, V>(f: function(U) -> V, g: function(T) -> U) -> function(T) -> V {
return function(x: T) -> V {
return f(g(x))
}
}
let square = (x: int) => x * x
let double = (x: int) => x * 2
let toString = (x: int) => x.toString()
// Compose functions
let squareThenDouble = compose(double, square)
let squareThenDoubleThenString = compose(toString, squareThenDouble)
print(squareThenDouble(3)) // 18 (3² * 2)
print(squareThenDoubleThenString(4)) // "32" (4² * 2 → string)
Memoization
// Memoization decorator
function memoize<T, R>(func: function(T) -> R) -> function(T) -> R {
let mut cache = {}
return function(input: T) -> R {
let key = input.toString()
if key in cache.keys {
return cache[key]
}
let result = func(input)
cache[key] = result
return result
}
}
// Optimize slow fibonacci with memoization
let memoFibonacci = memoize(function(n: int) -> int {
if n <= 1 return n
return memoFibonacci(n - 1) + memoFibonacci(n - 2)
})
// Now large numbers calculate quickly
print(memoFibonacci(40)) // Calculated quickly
🛡️ Function Optimization and Best Practices
1. Using Pure Functions
// Good: Pure function
function calculateTax(income: float, taxRate: float) -> float {
return income * taxRate
}
// Avoid: Function with side effects
let mut globalCounter = 0
function badFunction(value: int) -> int {
globalCounter += 1 // Side effect!
return value * 2
}
// Good alternative: Return state
function goodFunction(value: int, currentCounter: int) -> { result: int, newCounter: int } {
return {
result: value * 2,
newCounter: currentCounter + 1
}
}
2. Function Naming and Structure
// Clear function names
function validateUserEmail(email: string) -> bool {
return email.contains("@") && email.contains(".")
}
function calculateOrderTotal(orderItems: [{ price: float, quantity: int }]) -> float {
return orderItems
.map(item => item.price * item.quantity)
.reduce((total, amount) => total + amount, 0.0)
}
// Single responsibility principle
function parseUserData(rawData: string) -> { name: string, age: int } {
// Only responsible for parsing
let parts = rawData.split(",")
return {
name: parts[0].trim(),
age: parseInt(parts[1].trim())
}
}
function validateUserData(user: { name: string, age: int }) -> bool {
// Only responsible for validation
return user.name.length() > 0 && user.age > 0
}
3. Error Handling
// Safe function using Result type
function safeDivide(numerator: float, denominator: float) -> Result<float, string> {
if denominator == 0.0 {
return Err("Cannot divide by zero")
}
return Ok(numerator / denominator)
}
// Usage
match safeDivide(10.0, 2.0) {
case Ok(result) => print("Result: {result}")
case Err(error) => print("Error: {error}")
}
Functions and closures are core features of Topaz. Using them effectively allows you to write reusable and testable code! 🎯