Learning Cairo - Functions (3)

Learning Cairo - Functions (3)

Prerequisite

Install cairo-run.

Function Definitions

Functions are a fundamental feature in Cairo, and we are already familiar with the main function, which is the most important function in Cairo and serves as the entry point for running Cairo code. As we have seen before, functions are defined using the fn keyword in Cairo. In Solidity, the function keyword is used to define functions.

Unlike Solidity’s camelCase naming convention, Cairo uses snake_case for function and variable names. For example:

use debug::PrintTrait;

fn this_is_a_snake_case_function() {
    'Snake case function.'.print();
}

fn main() {
    'Hello, world!'.print();
    this_is_a_snake_case_function();
}

Similarly to Solidity, calling a function involves directly writing the function name and its arguments at the call site. In the example above, when calling the this_is_a_snake_case_function function, we simply write the function name. It’s worth noting that functions can be defined anywhere in the Cairo code, and there is no requirement for the order of their definitions relative to their calls, unlike in the C language.

We can try placing the function definition after its call, and it will still compile and execute correctly:

use debug::PrintTrait;

fn main() {
    'Hello, world!'.print();
    this_is_a_snake_case_function();
}

fn this_is_a_snake_case_function() {
    'Snake case function.'.print();
}

Function Parameters

Functions in Cairo can have parameters, which are part of the function’s signature. The syntax for parameters is similar to defining variables: we specify the parameter name followed by a colon and the parameter type. For example:

fn function_with_parameters(x: felt252, y: felt252) {
    x.print();
    y.print();
}

When calling the function, we simply provide the corresponding arguments of the expected types within parentheses:

use debug::PrintTrait;

fn main() {
    function_with_parameters(1, 2);
}

fn function_with_parameters(x: felt252, y: felt252) {
    x.print();
    y.print();
}

The code above compiles and runs successfully:

[DEBUG]                                 (raw: 1)

[DEBUG]                                 (raw: 2)

Run completed successfully, returning []

Functions with Return Values

Functions in Cairo can have return values. In Solidity, return values can be named or unnamed. For example:

function fun1() public view returns (uint256 a) {
    a = 1;
}

In Cairo, we don’t name the return values; we only need to define their types. We can use the -> symbol to specify the return value type. For example:

use debug::PrintTrait;

fn main() {
    let x = add(1_u8, 2_u8);
    x.print();
}

fn add(x: u8, y: u8) -> u8 {
    return x + y;
}

Statements and Expressions

Let’s revisit the previous example:

fn add(x: u8, y: u8) -> u8 {
    return x + y;
}

Now, let’s change it to:

fn add(x: u8, y: u8) -> u8 {
    x + y
}

Notice that there is no semicolon after x + y. If we try to compile and run it, it will still pass. Why is that?

This introduces the

concept of statements and expressions in Cairo:

  • Statements are instructions that perform operations but don’t return a value.
  • Expressions are evaluated and return a value.

We have already used statements and expressions. The process of defining variables, such as let y = 6;, is a statement.

Statements don’t return values. In other words, we cannot assign a let statement to another variable. For example:

fn main() {
    let x = (let y = 6);
}

This will result in an error:

error: Missing token TerminalRParen.
 --> print.cairo:4:14
    let x = (let y = 6);
             ^

error: Missing token TerminalSemicolon.
 --> main.cairo:4:14
    let x = (let y = 6);
             ^

error: Missing token TerminalSemicolon.
 --> main.cairo:4:23
    let x = (let y = 6);
                      ^

error: Skipped tokens. Expected: statement.
 --> main.cairo:4:23
    let x = (let y = 6);
                      ^

error: Skipped tokens. Expected: statement.
 --> main.cairo:4:24
    let x = (let y = 6);
                       ^

Error: failed to compile: main.cairo

The let y = 6 statement doesn’t return a value, so assigning it to x is meaningless. This is different from other languages like C, where such an operation is allowed:

x = y = 1;

But it is not allowed in Cairo.

Earlier, we mentioned that expressions return values. 1 + 2 is an expression that returns 3. Expressions can be part of a statement. For example, let x = 1 + 2; is a statement, but 1 + 2 within it is an expression.

Consider the following example:

use debug::PrintTrait;
fn main() {
    let y = {
        let x = 3;
        x + 1
    };

    y.print();
}

The block of code:

{
    let x = 3;
    x + 1
};

is assigned as a value to y, indicating that it is an expression. Notice that there is no semicolon after x + 1. If we were to add a semicolon, it would become a statement, and no value would be returned, making it impossible to assign the result.

Now, let’s revisit the previous example:

use debug::PrintTrait;

fn main() {
    let x = add(1_u8, 2_u8);
    x.print();
}

fn add(x: u8, y: u8) -> u8 {
    x + y
}

Since x + y is an expression that returns a value, Cairo helps us save some effort by eliminating the need to explicitly write a return statement. We can simply write the expression itself.

Summary

Functions are a fundamental feature in Cairo, similar to other programming languages. Function names should use snake_case, and Cairo’s expression feature allows us to omit the return statement.

You can star our repository, we will closely update it alongside StarkNet rolls out 1.0 fully, or join our Discord if you have any questions or want to contribute.

Call out StarkNet Beta Testers!

Reddio is building developer tools for StarkNet to help you accelerate the process to develop StarkNet applications. We are inviting all of StarkNet developers to join our beta testing group, try out brand-new features and tell us what you think.

https://share.hsforms.com/1E88oQkqMSJifUV1CqR_WrQd30xn

Low latency and free Starknet node awaits!

For a limited time, Reddio is offering unrestricted access to its high-speed StarkNet Node, completely free of charge. This is an unparalleled opportunity to experience the fastest connection with the lowest delay. All you need to do is register an account on Reddio at https://dashboard.reddio.com/ and start exploring the limitless possibilities.

You can discover why Reddio claims the fastest connection by reading more here.