Table of Contents

Parameters, overloading, and operators

Parameters describe the values a function accepts. Defaults and overloads let an API support common variations without requiring a different name for every call, while operators let suitable domain types use familiar expression syntax.

Method, constructor, and accessor parameters are immutable by default. They behave like let bindings: the compiler rejects assignments that attempt to rebind the parameter name. Add the var modifier when a parameter must be reassigned inside the body—for example, to reuse a scratch variable or to satisfy an out contract.

func clamp(min: int, value: int, max: int) -> int {
    // value = ...    // error: parameters are immutable by default
    return Math.Max(min, Math.Min(value, max))
}

func TryParse(text: string, out result: int) -> bool {
    result = 0      // ok: the parameter explicitly opts into mutation
    /* ... */
}

Declaring a parameter with ref, out, or in passes the argument by reference. The callee receives an alias to the caller's storage and callers supply such arguments with the address-of operator &expr. Plain parameters are readonly. ref parameters can be read and assigned, in parameters are readonly aliases, and out parameters must be assigned before the method returns. These modifiers already imply by-reference passing, so their declared types stay plain: use ref value: int, not ref value: &int. Explicit &Type parameters remain available when the by-reference type itself is the intended type annotation.

func Increment(ref value: int) -> () {
    value = value + 1
}

var total = 41
Increment(ref total)
Console.WriteLine(total) // prints 42

Low-level APIs may additionally use scoped parameters to restrict managed reference lifetimes. This is a specialized memory-safety feature; see Ref structs and ref safety for its syntax and escape rules.

Method overloading

Use overloading when the same operation makes sense for different sets or types of arguments.

Functions and methods may share a name as long as their parameter counts or types differ. Overload resolution selects the best match based on argument types, out/by-ref modifiers, and nullability. Ambiguous calls produce a diagnostic.

class Printer {
    func Print(x: int) -> () => Console.WriteLine(x)
    func Print(x: string) -> () => Console.WriteLine(x)
}

Print(42)
Print("hi")

Default parameter values

Use a default value when most callers should be able to omit an optional argument.

Methods, constructors, and other function-like members may specify default values for trailing parameters using = expression. Optional parameters follow the same rules as top-level functions: once a parameter provides a default, all subsequent parameters in the list must also supply defaults. The expression is restricted to compile-time constants—literals (including null), parenthesized literals, or unary +/- applied to numeric literals—and the resulting value must convert to the parameter type using an implicit conversion. When the expression fails these checks, the compiler reports an error and treats the parameter as required.

Operator declarations

Types can define operators when an operation has a clear meaning in ordinary expression syntax, such as adding two vectors.

Classes and structs can declare overloadable operators using function-style syntax where the operator token is the function name: static func <operator>(...) -> .... Supported tokens are +, -, *, /, %, ^, &, &&, and, |, ||, or, <<, >>, ==, !=, <, <=, >, >=, !, ~, ++, --. Operators mirror methods: they take a parenthesized parameter list, optional return-type arrow, and either a block body or expression body. The parameter count must match the chosen operator (unary or binary). Operator declarations are supported in classes, structs, and extensions.

class Vector {
    static func +(left: Vector, right: Vector) -> Vector => Add(left, right)
    static func -(value: Vector) -> Vector { /* ... */ }
}

Conversions follow the same style: static func implicit(value: SourceType) -> TargetType and static func explicit(value: SourceType) -> TargetType. These conversion members are resolved using the same lookup rules as other static members.

For null checks, prefer is null / is not null when you need strict nullability narrowing. Raven's analyzer recommends these forms over == null/!= null and provides a code fix. Pointer-like comparisons are excluded from that recommendation.

Invocation operator

An invocation operator makes an object callable. This is useful for objects whose main job is to apply a configured operation.

Declaring a method named self makes instances of the type invocable with the call operator ().

class Adder {
    func self(x: int, y: int) -> int => x + y
}

val add = Adder()
val sum = add(1, 2) // calls self(1, 2)

Invocation operators can themselves be overloaded by providing multiple self methods with different parameter signatures.