Functions

In Luwu, functions are values. You can store them in variables and tables, pass them to other functions and create new ones while the program runs.

Declaring and calling

Input
const function greet(name: string): string
    return `Hello, {name}!`
end

print(greet("Ada"))
Output
Hello, Ada!

const function declares a function that can't be reassigned. The local function you'll see in Lua and Luau code works in Luwu too. name: string says the parameter name takes a string and the : string after the parentheses says the function returns one. return ends the function and hands its value back to the caller.

Arguments

A missing argument is nil and an extra one is ignored. Luwu's type checker reports both before the code runs. Give a parameter a default value for calls that leave it out:

Input
const function cheer(message: string, times = 1)
    for _ = 1, times do
        print(message)
    end
end

cheer("go!")
cheer("again!", 2)
Output
go!
again!
again!

Default Arguments covers defaults for functions and class constructors in more depth.

Returning several values

A function can return more than one value. List them after return and receive them with several names on the left of =:

Input
const function min_max(numbers: { number }): (number, number)
    local low, high = math.huge, -math.huge
    for _, n in numbers do
        low = math.min(low, n)
        high = math.max(high, n)
    end
    return low, high
end

const low, high = min_max({ 72, 95, 88 })
print(`{low} to {high}`)
Output
72 to 95

Every value is kept only when the call comes last in a list of expressions. Anywhere else the call is cut down to its first value:

Input
const function pair(): (string, string)
    return "a", "b"
end

const last = { pair() }
const not_last = { pair(), "c" }
print(table.concat(last, " "))
print(table.concat(not_last, " "))
Output
a b
a c

Functions are values

A function written without a name is an anonymous function. It's a value like any other and most often gets passed straight to another function. table.sort takes one that says whether a goes before b:

Input
type Player = { name: string, score: number }

const players: { Player } = {
    { name = "Ada", score = 72 },
    { name = "Grace", score = 95 },
    { name = "Alan", score = 88 },
}
table.sort(players, function(a: Player, b: Player): boolean
    return a.score > b.score
end)
print(players[1].name)
Output
Grace

Functions can be stored in tables too. Luwu lets you declare them by name inside a table literal.

Closures

A function created inside another function can use the outer function's locals and keeps them alive after the outer function returns. Such a function is called a closure. Each call to make_counter below creates a new count for its counter:

Input
const function make_counter(): () -> number
    local count = 0
    return function()
        count += 1
        return count
    end
end

const next_ticket = make_counter()
next_ticket()
next_ticket()
print(next_ticket())
Output
3

Any number of arguments

A function that ends its parameters with ... takes any number of arguments. { ... } collects them into an array:

Input
const function sum(...: number): number
    local total = 0
    for _, n in { ... } do
        total += n
    end
    return total
end

print(sum(1, 2, 3, 4))
Output
10

Method calls

Calling with a colon passes the value before it as the first argument. name:upper() means string.upper(name) and account:deposit(5) means account.deposit(account, 5). Strings get their methods from the string library this way:

Input
const name = "nyla"
print(name:upper())
print(("meow"):rep(3))
Output
NYLA
meowmeowmeow

In Luwu, methods on your own data usually come from classes. A class groups data with the methods that work on it and protects that data from changes that would make it invalid.