v0.4.0

Function declarations

A function gives a block of statements a name, a list of typed parameters and, optionally, a result type. Calling it runs the block with the arguments bound to the parameters, and the call is worth the value the block returns.

function   = [ attributes ] [ "pub" ] [ "unsafe" ] "func" name [ type-parameters ]
             "(" [ parameter { "," parameter } [ "," ] ] ")"
             [ "->" type ] [ "throws" type ] block
parameter  = name ":" type [ "=" expression ]
           | name ":" type "..."
func Add(left: int, right: int) -> int {
    return left + right;
}
PartIn AddMeaning
NameAddAn identifier; PascalCase by convention
Parametersleft: int, right: intname: Type each, separated by commas; a trailing comma is allowed
Result type-> intThe type of the value the function returns; omitted when there is none
Error typenonethrows E after the result, when the function can fail
Body{ return left + right; }A block

Parameters, default values and variadic parameters are described in Parameters. A name in angle brackets after the function name declares a type parameter, which makes the function generic.

Where functions are declared

PlaceDeclares
The top level of a fileA free function of the package's root module
A module A::B { } blockA free function of that module — see Modules
An extend T { } blockA method, constructor, operator or destructor of T
An extern { } blockA foreign function, without a body — see FFI
asm funcA function whose body is assembly — see Assembly

unsafe func declares a function whose caller must uphold something the compiler cannot check; a call to it needs an unsafe context — see Pointers. Every other function needs a body. A signature ending in ; is refused:

error: function 'Later' has no body

Declaration order does not matter: a function may call one declared further down the file, or in another file of the package. pub makes a function visible to other packages; see Visibility.

The result

WrittenThe function
no ->Returns nothing. A bare return; leaves early; reaching the closing brace returns
-> TReturns a T. Every path through the body must end in return with a value
-> ()Returns the unit value ()
-> T throws E, throws ECan throw an E: it returns a T (or completes with ()) or throws

Several values are returned as a tuple, an absent result as an optional.

func Greet(name: char8[..]) {
    if name.length == 0 {
        return;
    }
    PrintLine("Hello, {}!", name);
}

func Divide(dividend: int, divisor: int) -> (int, int) {
    return (dividend / divisor, dividend % divisor);
}

The compiler checks that a function with a result type returns on every path, and that a function without one never returns a value:

error: function 'Sign' must return a value of type 'int' on every control-flow path
error: 'return' cannot have a value in a function with no return type

A function that declares throws E and no result type completes with () when it returns or reaches its end. Leaving out the result type of a function that does not throw is not the same as writing -> (). Only a unit-returning function produces a value of type () that can be stored or passed; a call to a function without a result is written as a statement on its own. See return for the statement itself.

Calls

A call is the function's name followed by one argument per parameter, in parentheses and in order. An argument may be labeled with its parameter's name, as in Clamp(150, high: 255) — see Named arguments. Arguments are evaluated from left to right, then bound to the parameters, and the body runs:

func Note(label: char8[..], value: int) -> int {
    PrintLine("evaluating {}", label);
    return value;
}

func Main() -> int {
    // Prints "evaluating first", then "evaluating second", then 12.
    PrintLine("{}", Pair(Note("first", 1), Note("second", 2)));
    return 0;
}

func Pair(first: int, second: int) -> int {
    return first * 10 + second;
}

A call is an expression of the result type and may appear wherever a value of that type fits — as an argument to another call, in an operator, on the right of a binding.

Each argument must convert to its parameter's type as an initializer would: an integer widens to a wider integer of the same signedness, and an unsuffixed integer literal takes the integer type of its parameter, so Half(9) works for a uint8 parameter. A function may call itself, directly or through others; each call has its own parameters and locals.

A call to a function that declares throws is a throw site and is marked with try, as in let n = try Parse(text);; an unmarked one is call to 'Parse' can throw 'ParseError' but is not marked with 'try'. See Errors.

Rules and errors

MistakeError
An argument of another typeargument 1 to 'Square' has type 'float64', but parameter 'value' requires 'int'
Too many or too few argumentscall to 'Square' expects 1 argument, but 2 were provided
A name in the wrong casename 'square' is not defined in this scope, with did you mean 'Square'?
A missing return on some pathfunction 'Sign' must return a value of type 'int' on every control-flow path
A value returned from a function without a result'return' cannot have a value in a function with no return type
A body-less signature outside externfunction 'Later' has no body

Names are case-sensitive. Several functions may share a name when their parameters differ; see Overloading.

See also