Functions

Functions are essential in programming as they enable code modularity, reuse, and organization. By encapsulating specific tasks into discrete units, functions allow developers to write cleaner, more manageable code. They promote code reuse by allowing the same block of code to be executed from multiple places within a program, reducing redundancy and potential for errors, as well as enhancing readability and maintainability.

Compiler-Defined Functions

Some functions will be automatically defined by the compiler based on the providers you have included in your script. These can be called just like user defined functions

Function Definitions

Before being able to call a function, you must define it. We allow functions to be declared anywhere in a script that is not nested within another function, if/else block, or probe.

Formal Syntax: ID ~ "(" ~ (( type ~ ID ) ~ ("," ~ type ~ ID )*) ? ~ ")" ~ ("->" ~ type) ? ~ block

If there is no declared return type, denoted by "->" followed by a type before the block, the default return type is () -- this is effectively "void" or "empty tuple" It is required to have a return statement for all possible flows through a function if it has a non-void return type and to return a value whose type must match the return type of the function.

Examples of Function Definitions:

//This is a function without a return type
i32 i = 0; 
my_function(i32 param) {
    i = param;
    return; //this is not required, but allowed
    i++; //this code is unreachable 
}
//This is another function without a return type
i32 count;
my_function() {
    count++; //function does not require a return, as it has no return type
}
my_function2() -> () { // This is functionally equivalent to my_function
    count++;
}
//here are functions with a return type
dummy_fn() -> i32 {
    return 5;
}
add_ints(i32 a, i32 b) -> i32 {
    return a + b;
}
larger_than_5(i32 num) -> bool {
    return num > 5;
}
//Here is an example of functions using if/else logic and function calls (see below)
i32 my_var = 5;
my_function(bool param) -> i32 {
    if(param){
        my_var++;
        return 0;
    }else{
        my_var--;
        return my_var;
    }
    //as all possible flows through the function have a return statement, all later code will be unreachable and does not require a return statement.
}

Function Calls

After a function is declared, either via the compiler or inside the script, they can be used within other functions and within probes. When called, functions execute the code specified in their definition and return a value with type matching the type of that function

NOTE: You cannot call functions outside of probes or other functions

Formal Syntax: ID ~ "(" ~ ( arg )? ~ ( "," ~ arg )* ~ ")"

Examples:

i32 a = 0;
inner_fn() {
    a++;
}
outer_fn() -> i32 {
    inner_fn();
    return a + 5;
}
//"BEGIN" is our probe that executes on wasm startup
BEGIN {
    inner_fn(); // call without assigning to something when void
    i32 local1 = outer_fn(); // call with assigning to a local when non-void
    outer_fn(); // you can call without assigning to something when non-void
}
larger_than_5(i32 num) -> bool {
    return num > 5;
}
//"BEGIN" is our probe that executes on wasm startup
BEGIN{
    bool local1 = larger_than_5(6);
}