Flexible Parameters
Declaring a default value for a parameter makes that argument optional at the call site. The value is evaluated on each call that omits the argument, so dynamic expressions work correctly:
Single parameter with default, multiple defaults, and a method with a default in impl.
03-default-params.zolo
// Feature: Parameters with default values
// Syntax: `fn f(p: T = expr)` — caller may omit them.
// When to use: ergonomic API with optional config, avoid
// overloads and intermediate constructors.
// One default parameter at the end.
fn greet(name: str = "World") -> str {
return "Hello, {name}!"
}
print(greet()) // Hello, World!
print(greet("Zolo")) // Hello, Zolo!
// Multiple defaults — all positional.
fn connect(host: str = "localhost", port: int = 8080) -> str {
return "{host}:{port}"
}
print(connect()) // localhost:8080
print(connect("api.example.com")) // api.example.com:8080
print(connect("api.example.com", 443)) // api.example.com:443
// A default may use an expression — it is evaluated on EVERY
// call that omits the argument.
fn label(prefix: str, n: int = 0) -> str {
return "{prefix}-{n}"
}
print(label("item")) // item-0
print(label("item", 7)) // item-7
// Methods accept defaults too.
struct Counter {
value: int,
}
impl Counter {
fn new() -> Counter {
return Counter { value: 0 }
}
fn add(self, n: int = 1) -> int {
self.value = self.value + n
return self.value
}
}
let c = Counter::new()
print(c.add()) // 1
print(c.add()) // 2
print(c.add(10)) // 12
Varargs (args: ...T) allow receiving any number of arguments
of the same type. Inside the function, the parameter behaves like a normal
array — iterable with for or indexable:
sum, log with fixed level + variable parts, max_of and join_csv.
04-varargs.zolo
// Feature: Varargs (variadic parameters)
// Syntax: `fn f(args: ...T)` — `...` before the type.
// When to use: accept N arguments of the same type, in
// `printf` or `Array.of` style — without wrapping in a literal.
use std::Array
// Sum N integers.
fn sum(nums: ...int) -> int {
var total = 0
for n in nums {
total += n
}
return total
}
print(sum()) // 0
print(sum(1)) // 1
print(sum(1, 2, 3)) // 6
print(sum(1, 2, 3, 4, 5, 6, 7)) // 28
// You can mix normal params before the vararg.
fn log(level: str, parts: ...str) {
var buf = "[{level}] "
for p in parts {
buf = buf + p + " "
}
print(buf)
}
log("info", "user", "logged", "in")
// expected: [info] user logged in
// Inside the function, `nums` is a regular array.
fn max_of(xs: ...int) -> int {
var hi = xs[0]
for x in xs {
if x > hi { hi = x }
}
return hi
}
print(max_of(3, 1, 4, 1, 5, 9, 2, 6)) // 9
// Varargs with strings: common in loggers and formatters.
fn join_csv(items: ...str) -> str {
var out = ""
var first = true
for it in items {
if !first { out = out + "," }
out = out + it
first = false
}
return out
}
print(join_csv("a", "b", "c")) // a,b,c
Challenge
Combine both features: write repeat(msg: str, n: int = 3) that prints
msg exactly n times. Call it without the second argument and then with 5.
See also