Functions

Functions in Cyrus are defined using the func keyword, followed by the function name, parameters, and return type.


Basic Function Example

Here's a simple example of a function that adds two integers:

func sum(x: int, y: int) int {
    return x + y;
}

Recursion

func main() {
    fibonacci(10); // expected value: 55
}

func fibonacci(n: int) int {
    if (n == 0) {
        return 0;
    }
    else if (n == 1) {
        return 1;
    }
    else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}
  • Local functions cannot be called from outside their enclosing function.
  • You can call a local function just like any normal function, but only after its declaration.

Function Access Specifiers

In Cyrus, functions can be declared with access specifiers that control their visibility and behavior.
These specifiers are placed before the func keyword.

  • extern - Declares that the function is defined outside the current module (e.g., in a C library). Useful for interoperability.
extern func printf(format: const char*, ...) int32;

Only valid for declarations.

  • public Makes the function visible outside the current module. Without public, a function is private by default and can only be used within the same module.
public func sum(a: int, b: int) int {
    return a + b;
}
  • inline Hints to the compiler that the function body should be expanded inline at call sites (for performance). This is most effective with small utility functions.
inline func square(x: int) int {
    return x * x;
}
  • public inline A combination: visible outside the module and a candidate for inlining.
public inline func abs(x: int) int {
    if (x < 0) {
        return -x;
    } else {
        return x;
    }
}
  • public extern Declares an external function that is also exported from the current module. This is commonly used when exposing bindings or APIs.
public extern func sin(x: float64) float64;

Variadic Arguments

Cyrus supports two kinds of variadic arguments, allowing functions to accept a variable number of parameters.


C-style Variadic Arguments

C-style variadic functions use the ... notation, just like in C. These are typically used for interfacing with C libraries (e.g., printf) or when type safety is not a concern.

extern func printf(format: const char*, ...) int;

func main() {
    printf("Hello %s, number = %d\n", "Cyrus", 42);
}
  • Use this style primarily for compatibility with C and low-level APIs.
  • Inside the function body, such arguments are accessed with platform-specific varargs handling (similar to C's va_list).

Typed Variadic Arguments (Not implemented yet.)

Typed variadic functions allow specifying one type that repeats for an arbitrary number of arguments. This gives type safety and better compiler optimizations.

func sum_all(nums: int...) int {
    // Coming soon.
}

func main() {
    #s: int = sum_all(1, 2, 3, 4, 5);
    println(s); # Output: 15
}

Anonumous Functions

Coming soon...


Function ABI Name

Cyrus allows you to specify a different ABI-level (linker) name for a function than its Cyrus name. This is done using the as keyword after the declaration.

extern func printf(fmt: string, ...) int as my_printf;

func main() {
    my_printf("Hello, %s!\n", "Cyrus");
}
  • The function is declared as printf at the ABI level, so it links against the real printf symbol in the C standard library.
  • Inside Cyrus, however, the function is referred to as my_printf.
  • This allows you to avoid naming conflicts or to wrap existing library functions under more descriptive names.