Function

Function#

Function is the only place of execution in Rogue. Function starts with the fun keyword which is followed by function name, parentheses for arguments and curly braces for body.

fun function_name(arg1: u64, arg2: bool): u64 {
// function body
}

You have already seen some in previous chapters. And now you will learn how to use them.

Note: in Rogue functions should be named in snake_case - lowercase with underscores as word separators.

Function in script#

Script block can contain only one function which is considered main. This function (possibly with arguments) will be executed as a transaction. It is very limited: it cannot return value and should be used to operate other functions in already published methods.

Here's an example of simple script which checks if address exists:

script {
use 0x1::Account;
fun main(addr: address) {
assert(Account::exists(addr), 1);
}
}

This function can have arguments: in this case it is addr argument with type address, also it can operate imported methods.

Note: as there's only one function, you can call it any way you want. Though you may want to follow general programming concepts and call it main

Function in method#

While script context is fairly limited, full potential of functions can only be seen in a method. Let's go through it again: method is a published set of functions and types (we'll get to it in the next chapter) which solves one or many tasks.

In this part we'll create a simple Math method which will provide users with a basic set of mathematical functions and a few helper methods. Most of this could be done without using a method, but our goal is education!

method Math {
fun zero(): u8 {
0
}
}

First step: we've defined a method named Math with one function in it: zero(), which returns 0 - a value of type u8. Remember expressions? There's no semicolon after 0 as it is the return value of this function. Just like you would do with block. Yeah, function body is very similar to block.

Function arguments#

This should be clear by now, but let's repeat. Function can take arguments (values passed into function). As many as needed. Every argument has 2 properties: name - its name within a function body, and type - just like any other variable in Rogue.

Function arguments - just like any other variables defined within a scope - live only within function body. When the function block ends, no variables remain.

method Math {
public fun sum(a: u64, b: u64): u64 {
a + b
}
fun zero(): u8 {
0
}
}

What's new in our Math: function sum(a,b) which sums two u64 values and returns a result - u64 sum (type can't change).

Let's state few syntax rules:

  1. Arguments must have types and must be separated by comma
  2. Function return value is placed after parentheses and must follow a colon

Now how would we use this function in script? Through import!

script {
use 0x1::Math; // used 0x1 here; could be your address
use 0x1::Debug; // this one will be covered later!
fun main(first_num: u64, second_num: u64) {
// variables names don't have to match the function's ones
let sum = Math::sum(first_num, second_num);
Debug::print<u64>(&sum);
}
}

Keyword return#

Keyword return allows you to stop function execution and return value. It is supposed to be used with if condition, as that is the only way to make conditional switch in control flow.

method M {
public fun conditional_return(a: u8): bool {
if (a == 10) {
return true // semi is not put!
};
if (a < 10) {
true
} else {
false
}
}
}

Multiple return values#

In previous examples we've experimented with functions with no return value or with single. But what if told you that you can return multiple values of any type? Curious? Let's proceed!

To specify multiple return values you need to use parentheses:

method Math {
// ...
public fun max(a: u8, b: u8): (u8, bool) {
if (a > b) {
(a, false)
} else if (a < b) {
(b, false)
} else {
(a, true)
}
}
}

This function takes two arguments: a and b and returns two values: first is the max value from two passed and second is a bool - whether numbers entered are equal. Take closer look at the syntax: instead of specifying single return argument we've added parenteses and have listed return argument types.

Now let's see how we can use the result of this function in another function in the script.

script {
use 0x1::Debug;
use 0x1::Math;
fun main(a: u8, b: u8) {
let (max, is_equal) = Math::max(99, 100);
assert(is_equal, 1)
Debug::print<u8>(&max);
}
}

In this example we've destructed a tuple: created two new variables with values and types of return values of function max. Order is preserved and variable max here gets type u8 and now stores max value, whereas is_equal is a bool.

Two is not the limit - number of returned arguments is up to you, though you'll soon learn about structs and see alternative way to return complex data.

Function visibility#

When defining a method you may want to make some functions accessible by other developers and some to remain hidden. This is when function visibility modifiers come to play.

By default every function defined in a method is private - it cannot be accessed in other methods or scripts. If you've been attentive, you may have noticed that some of the functions that we've defined in our Math method have keyword public before their definition:

method Math {
public fun sum(a: u64, b: u64): u64 {
a + b
}
fun zero(): u8 {
0
}
}

In this example function sum() is accessible from outside when method is imported, however function zero() is not - it is private by default.

Keyword public changes function's default private visibility and makes it public - i.e. accessible from outside.

So basically if you didn't make sum() function public, this wouldn't be possible:

script {
use 0x1::Math;
fun main() {
Math::sum(10, 100); // won't compile!
}
}

Access local functions#

There would not be any sense in making private functions if they could not be accessed at all. Private functions exist to do some internal work when public functions are called.

Private functions can only be accessed in the method where they're defined.

So how do you access functions in the same method? By simply calling this function like it was imported!

method Math {
public fun is_zero(a: u8): bool {
a == zero()
}
fun zero(): u8 {
0
}
}

Any function defined in a method is accessible by any function in the same method no matter what visibility modifiers any of them has. This way private functions can still be used as calls inside public ones without exposing some private features or too risky operations.

Native functions#

There's a special kind of functions - native ones. Native functions implement functionality which goes beyond Rogue's possibilities and give you extra power. Native functions are defined by VM itself and may vary in different implementations. Which means they don't have implementation in Rogue syntax and instead of having function body they end with a semicolon. Keyword native is used to mark native functions. It does not conflict with function visibility modifiers and the same function can be native and public at the same time.

Here's an example from Dijet's standard library.

method Signer {
native public fun borrow_address(s: &signer): &address;
// ... other functions to add ...
}