« Previous: Control Flow · Guide Index · Next: Lambdas and Closures »
Functions group statements behind a name so you can reuse them. They are
introduced with the func keyword.
func greet(name) {
print("hello", name)
}
greet("Ali") # hello Ali
A function returns a value with return:
func add(a, b) {
return a + b
}
print(add(3, 4)) # 7
A function that reaches its end without a return produces null.
An argument may be named at the call site with name = value. Named arguments
can appear in any order and may be mixed with positional ones:
func box(w, h) {
return w * h
}
print(box(h = 3, w = 4)) # 12
print(box(4, h = 3)) # 12
The names must match the function's parameters. A function that collects extra
named arguments with **kwargs receives any names it does not declare (see
Variadic parameters).
A parameter may be annotated with a type. The annotation documents intent and is enforced when the function is called:
func add(a:int, b:int) {
return a + b
}
print(add(2, 3)) # 5
# add("x", 1) # error: wrong argument type
The available type names match type(): int, float, string, bool,
null, list, map.
Omitting the annotation accepts any value:
func show(value) {
print("value:", value)
}
show("text")
show(42)
A parameter can declare a default, used when the argument is omitted:
func say(text:string, ending:string = " world") {
return text + ending
}
print(say("hello")) # hello world
print(say("hello", " Quanto")) # hello Quanto
A parameter can accept more than one type using |. Use isinstance to branch
on the actual type:
func greet_any(name:string|int) {
if isinstance(name, "int") {
print("hello number", name)
} else {
print("hello", name)
}
}
greet_any("Sara") # hello Sara
greet_any(42) # hello number 42
Unions can list several types:
func show(value:string|int|bool) {
print("value:", value)
}
A parameter written *rest collects all remaining positional arguments into a
list:
func collect(first, *rest) {
print("first:", first)
print("rest:", rest)
}
collect("a", "b", "c", "d")
# first: a
# rest: ['b', 'c', 'd']
A parameter written **info collects all remaining keyword arguments into a map:
func profile(name:string, **info) {
print("name:", name)
print("age:", info["age"])
print("city:", info["city"])
}
profile("Sara", age=20, city="Tehran")
Functions may call themselves:
func factorial(n) {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
print(factorial(5)) # 120
ever_return(fn) inspects a function and reports whether it can produce a value.
A function that only prints, or that never finishes (for example one that calls
exit), reports false:
func gives_number() {
return 2
}
func gives_null() {
}
func stops() {
exit()
}
print(ever_return(gives_number)) # true
print(ever_return(gives_null)) # false
print(ever_return(stops)) # false
Because functions are values, they can be passed to other functions and stored
in variables — this is exactly what map, filter, and find rely on. See
Lambdas and Closures.
Lambdas and Closures covers anonymous functions and environment capture.
« Previous: Control Flow · Guide Index · Next: Lambdas and Closures »