Types with Abilities

Types with Abilities#

Rogue has unique type system which is very flexible and customizable. Each type can have up to 4 abilities which define how values of this type can be used, dropped or stored.

There are 4 type abilities: Copy, Drop, Store and Key.

Simply described:

  • Copy - value can be copied (or cloned by value).
  • Drop - value can be dropped by the end of scope.
  • Key - value can be used as a key for global storage operations.
  • Store - value can be stored inside global storage.

On this page we will go through Copy and Drop abilities in detail; more context over Key and Store abilities will be given when we get to Resources chapter.

Abilities syntax#

Primitive and built-in types' abilities are pre-defined and unchangeable: integers, vector, addresses and boolean values have copy, drop and store abilities

However when defining structs you can specify any set of abilities using this syntax:

struct NAME has ABILITY [, ABILITY] { [FIELDS] }

Or by example:

method Library {
// each ability has matching keyword
// multiple abilities are listed with comma
struct Book has store, copy, drop {
year: u64
}
// single ability is also possible
struct Storage has key {
books: vector<Book>
}
// this one has no abilities
struct Empty {}
}

Struct with no Abilities#

Before we jump into how to use abilities and what they bring into the language, let's see what happens if there's a type with no abilities.

method Country {
struct Country {
id: u8,
population: u64
}
public fun new_country(id: u8, population: u64): Country {
Country { id, population }
}
}
script {
use {{sender}}::Country;
fun main() {
Country::new_country(1, 1000000);
}
}

If you try to run this code, you'll get the following error:

error:
โ”Œโ”€โ”€ scripts/main.rogue:5:9 โ”€โ”€โ”€
โ”‚
5 โ”‚ Country::new_country(1, 1000000);
โ”‚ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot ignore values without the 'drop' ability. The value must be used
โ”‚

Method Country::new_country() creates a value; this value is not passed anywhere and automatically dropped when function ends; but Country type doesn't have Drop ability, and it fails. Now let's change our struct definition and add Drop Ability.

Drop#

Using abilities syntax we add has drop specifying drop ability for this struct. All of the instances of this struct will have drop ability and hence will be droppable.

method Country {
struct Country has drop { // has <ability>
id: u8,
population: u64
}
// ...
}

Now, when struct Country can be dropped, our script can be run.

script {
use {{sender}}::Country;
fun main() {
Country::new_country(1, 1000000); // value is dropped
}
}

Note: Drop ability only defines drop behavior. Destructuring does not require Drop.

Copy#

We learned how to create new instances of struct Country and drop them. But what if we wanted to create a copy? By default, structs are passed by value; and to create a copy of this struct we will use keyword copy (you will learn more about this behavior in the next chapter):

script {
use {{sender}}::Country;
fun main() {
let country = Country::new_country(1, 1000000);
let _ = copy country;
}
}
โ”Œโ”€โ”€ scripts/main.rogue:6:17 โ”€โ”€โ”€
โ”‚
6 โ”‚ let _ = copy country;
โ”‚ ^^^^^^^^^^^^ Invalid 'copy' of owned value without the 'copy' ability
โ”‚

As you could expect, making a copy of type without copy ability failed. Compiler message is clear:

method Country {
struct Country has drop, copy { // see comma here!
id: u8,
population: u64
}
// ...
}

With that change code above would compile and run.

Summary#

  • Primitive types have store, copy and drop.
  • By default structs have no abilities.
  • Copy and Drop abilities define whether value can be copied and dropped respectively.
  • It is possible to set up to 4 abilities for a struct.