Function Calls

Positional arguments, named arguments, default parameters, methods, and generic calls.

Function calls use parentheses.

fn add(a: i32, b: i32) -> i32 {
    return a + b;
}

let value = add(20, 22);

Default Parameters

fn example(path: str, force: bool = false) -> i32 {
    if force {
        return path.size as i32;
    }
    return (path.size as i32) + 1;
}

let a = example("/tmp");
let b = example("/tmp", true);

Named Arguments

let value = add(a: 1, b: 2);

Named arguments are checked against parameter names and overload candidates. They must follow parameter order; use them to clarify a call or skip defaulted parameters, not to reorder required parameters.

fn open(path: str, mode: str = "r", buffered: bool = true) -> bool {
    _ = path;
    _ = mode;
    return buffered;
}

let ok = open("config.zx", buffered: false);

open(buffered: false, path: "config.zx") is rejected because the named arguments move backward through the parameter list.

Reference Arguments

Reference-typed arguments are explicit in ordinary calls. When a parameter expects &T or const &T, pass &value or another reference-valued expression.

fn add_one(value: &i32) {
    value = *value + 1;
}

fn main() {
    let count = 1;
    add_one(&count);
    assert count == 2;
}

Method receivers keep auto-borrowing for self: &T and self: const &T. Operator overload operands keep receiver-style borrowing because operator syntax has no explicit argument list. Non-receiver method arguments and callable values follow the ordinary explicit-borrow rule.

Borrowed View Arguments

Calls can borrow common text and byte inputs as views without extra overloads. This applies only while matching call arguments:

import std.bytes;
import std.hash;
import std.io;
import std.mem;
import {
    String
} from std.string;

fn text_len(value: str) -> usize {
    return value.size;
}

fn byte_len(value: bytes.Bytes) -> usize {
    return value.length;
}

fn main() {
    let text = try String("hello");
    let label = "hello";
    let raw = [65 as u8, 66 as u8, 67 as u8];
    let slice = mem.slice_of<u8>(raw.ptr, raw.length);

    assert text_len(text) == 5;
    assert byte_len("hello") == 5;
    assert byte_len(text) == 5;
    assert byte_len("{label}") == 5;
    assert byte_len(slice) == 3;
    assert hash.crc32.sum("hello") == 0x3610a686;

    let stream = io.MemoryStream();
    try stream.write("{label}");
    try stream.write(text);
    assert text.str() == "hello";
}

Supported call-only conversions are String and const &String to str, plus str, interpolated format strings, String, const &String, and [u8] slices to bytes.Bytes. These are borrowed, zero-copy views, so passing a String this way does not move it.

Stored views stay explicit. A declaration such as let data: bytes.Bytes = "abc" is rejected; use bytes.Bytes(...), text.str(), or text.utf8() when a view needs to be stored or returned.

Generic Calls

Generic arguments can be explicit or inferred from value arguments:

fn id<T>(value: T) -> T {
    return value;
}

let a = id<i32>(42);
let b = id("zynx");

Generic argument lists can contain integer literals for const generic parameters, for example SizedArray<i32, 3>. See Generics.