Skip to content

Commit

Permalink
feat(docs): add abilities section
Browse files Browse the repository at this point in the history
Signed-off-by: salaheldinsoliman <[email protected]>
  • Loading branch information
salaheldinsoliman committed Oct 25, 2024
1 parent ac9b15b commit 67c08d6
Show file tree
Hide file tree
Showing 11 changed files with 541 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Abilities: Introduction

Move has a unique type system which allows customizing _type abilities_.
In the [struct section](./struct.mdx), we introduced the `struct` definition and how to use it.
However, the instances of the `Artist` and `Record` structs had to be unpacked for the code to
compile. This is default behavior of a struct without _abilities_.

::: info
Throughout the documentation you will see struct definitions with abilities. This section will cover abilities in detail, how it works, and how to use it
in Move.
:::

## What are Abilities?

Abilities are a way to allow certain behaviors for a type. They are a part of the struct declaration
and define which behaviours are allowed for the instances of the struct.

## Abilities syntax

Abilities are set in the struct definition using the `has` keyword followed by a list of abilities.
The abilities are separated by commas. Move supports 4 abilities: `copy`, `drop`, `key`, and
`store`, each of them is used to define a specific behaviour for the struct instances.

```move
/// This struct has the `copy` and `drop` abilities.
struct VeryAble has copy, drop {
// field: Type1,
// field2: Type2,
// ...
}
```

## Overview

A quick overview of the abilities:

:::info
All of the built-in types, except references, have `copy`, `drop` and `store` abilities.
References have `copy` and `drop`.
:::

- `copy` - allows the struct to be _copied_. Explained in the [Ability: Copy](./copy.mdx)
chapter.
- `drop` - allows the struct to be _dropped_ or _discarded_. Explained in the
[Ability: Drop](./drop.mdx) section.
- `key` - allows the struct to be used as a _key_ in a storage. Explained in the
[Ability: Key](./key.mdx) chapter.
- `store` - allows the struct to be _stored_ in structs with the _key_ ability. Explained in the
[Ability: Store](./store.mdx) chapter.

While it is important to mention them here, we will go in detail about each ability in the following
chapters and give a proper context on how to use them.

## No abilities

A struct without abilities cannot be discarded, or copied, or stored in the storage. We call such a
struct a _Hot Potato_. It is a joke, but it is also a good way to remember that a struct without
abilities is like a hot potato - it can only be passed around and requires special handling. Hot
Potato is one of the most powerful patterns in Move, we go in detail about it in the
[Hot Potato](../patterns/hot-potato.mdx) chapter.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Abilities: Copy

In Move, the _copy_ ability on a type indicates that the instance or the value of the type can be
copied. While this behavior may feel very natural when working with numbers or other simple types,
it is not the default for custom types in Move. This is because Move is designed to express digital
assets and resources, and inability to copy is a key element of the resource model.

However, Move type system allows you to define custom types with the _copy_ ability.

```move
file=<rootDir>/docs/examples/move/move-overview/copy-ability.move#L8-L8
```

In the example above, we define a custom type `Copyable` with the _copy_ ability. This means that
instances of `Copyable` can be copied, both implicitly and explicitly.

```move
file=<rootDir>/docs/examples/move/move-overview/copy-ability.move#L8
```

In the example above, `a` is copied to `b` implicitly, and then explicitly copied to `c` using the
dereference operator. If `Copyable` did not have the _copy_ ability, the code would not compile, and
the Move compiler would raise an error.

## Copying and Drop

The `copy` ability is closely related to [`drop` ability](./drop.mdx). If a type has the
_copy_ ability, very likely that it should have `drop` too. This is because the _drop_ ability is
required to clean up the resources when the instance is no longer needed. If a type has only _copy_,
then managing its instances gets more complicated, as the values cannot be ignored.

```move
file=<rootDir>/docs/examples/move/move-overview/copy-ability.move#L25
```

All of the primitive types in Move behave as if they have the _copy_ and _drop_ abilities. This
means that they can be copied and dropped, and the Move compiler will handle the memory management
for them.

## Types with the `copy` Ability

All native types in Move have the `copy` ability. This includes:

- bool
- unsigned integers
- [vector](../../../../references/framework/move-stdlib/vector.mdx)
- [address](../../../../references/framework/move-stdlib/address.mdx)

All of the types defined in the standard library have the `copy` ability as well. This includes:

- [Option](../../../../references/framework/move-stdlib/option.mdx)
- [String](../../../../references/framework/move-stdlib/string.mdx)
- [TypeName](../../../../references/framework/move-stdlib/type_name.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Abilities: Drop

The `drop` ability - the simplest of abilities - allows the instance of a struct to be _ignored_ or
_discarded_. In many programming languages this behavior is considered default. However, in Move, a
struct without the `drop` ability is not allowed to be ignored. This is a safety feature of the Move
language, which ensures that all assets are properly handled. An attempt to ignore a struct without
the `drop` ability will result in a compilation error.

```move
file=<rootDir>/docs/examples/move/move-overview/abilities-drop.move#L5-L25
```


The `drop` ability is often used on custom collection types to eliminate the need for special
handling of the collection when it is no longer needed. For example, a `vector` type has the `drop`
ability, which allows the vector to be ignored when it is no longer needed. However, the biggest
feature of Move's type system is the ability to not have `drop`. This ensures that the assets are
properly handled and not ignored.

A struct with a single `drop` ability is called a _Witness_. We explain the concept of a _Witness_
in the [Witness and Abstract Implementation](../patterns/witness.mdx)
section.

## Types with the `drop` Ability

All native types in Move have the `drop` ability. This includes:

- bool
- unsigned integers
- [vector](../../../../references/framework/move-stdlib/vector.mdx)
- [address](../../../../references/framework/move-stdlib/address.mdx)

All of the types defined in the standard library have the `drop` ability as well. This includes:

- [Option](../../../../references/framework/move-stdlib/option.mdx)
- [String](../../../../references/framework/move-stdlib/string.mdx)
- [TypeName](../../../../references/framework/move-stdlib/type_name.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# The Key Ability

We already covered two out of four abilities -
[Drop](./drop.mdx) and [Copy](./copy.mdx). They affect the behaviour of the value in a
scope and are not directly related to storage. It is time to cover the `key` ability, which allows
the struct to be stored.

Historically, the `key` ability was created to mark the type as a _key in the storage_. A type with
the `key` ability could be stored at top-level in the storage, and could be _directly owned_ by an
account or address. With the introduction of the [Object Model](../../objects/object-model.mdx), the `key` ability
naturally became the defining ability for the object.


## Object Definition

A struct with the `key` ability is considered an object and can be used in the storage functions.
The Sui Verifier will require the first field of the struct to be named `id` and have the type
`UID`.

```move
public struct Object has key {
id: UID, // required
name: String,
}
/// Creates a new Object with a Unique ID
public fun new(name: String, ctx: &mut TxContext): Object {
Object {
id: object::new(ctx), // creates a new UID
name,
}
}
```

A struct with the `key` ability is still a struct, and can have any number of fields and associated
functions. There is no special handling or syntax for packing, accessing or unpacking the struct.

However, because the first field of an object struct must be of type `UID` - a non-copyable and
non-droppable type (we will get to it very soon!), the struct transitively cannot have `drop` and
`copy` abilities. Thus, the object is non-discardable by design.


## Types with the `key` Ability

Due to the `UID` requirement for types with `key`, none of the native types in Move can have the
`key` ability, nor can any of the [Standard Library](../../../../references/framework/move-stdlib/_category_.json) types.
The `key` ability is only present in the [IOTA Framework](../../../../references/framework/iota-framework/_category_.json) and
custom types.

## Next Steps

Key ability defines the object in Move, and objects are intended to be _stored_. In the next section
we present the `iota::transfer` module, which provides native storage functions for objects.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Ability: Store

## Definition

The `store` is a special ability that allows a type to be _stored_ in objects. This ability is
required for the type to be used as a field in a struct that has the `key` ability. Another way to
put it is that the `store` ability allows the value to be _wrapped_ in an object.

:::info
The `store` ability also relaxes restrictions on transfer operations. We talk about it more in the
[Custome Transfer Rules](../../objects/transfers/custom-rules.mdx) section.

Check warning on line 11 in docs/content/developer/iota-101/move-overview/structs-and-abilities/store.mdx

View workflow job for this annotation

GitHub Actions / typos / Spell Check with Typos

"Custome" should be "Custom" or "Customs" or "Costume" or "Customer".

Check warning on line 11 in docs/content/developer/iota-101/move-overview/structs-and-abilities/store.mdx

View workflow job for this annotation

GitHub Actions / docs-lint / Lint documentation

"Custome" should be "Custom" or "Customs" or "Costume" or "Customer".

Check warning on line 11 in docs/content/developer/iota-101/move-overview/structs-and-abilities/store.mdx

View workflow job for this annotation

GitHub Actions / typos / Spell Check with Typos

"Custome" should be "Custom" or "Customs" or "Costume" or "Customer".

Check warning on line 11 in docs/content/developer/iota-101/move-overview/structs-and-abilities/store.mdx

View workflow job for this annotation

GitHub Actions / docs-lint / Lint documentation

"Custome" should be "Custom" or "Customs" or "Costume" or "Customer".
:::

## Example

In previous sections we already used types with the `key` ability: all objects must have a `UID`
field, which we used in examples; we also used the `Storable` type as a part of the `Config` struct.
The `Config` type also has the `store` ability.

```move
/// This type has the `store` ability.
public struct Storable has store {}
/// Config contains a `Storable` field which must have the `store` ability.
public struct Config has key, store {
id: UID,
stores: Storable,
}
/// MegaConfig contains a `Config` field which has the `store` ability.
public struct MegaConfig has key {
id: UID,
config: Config, // there it is!
}
```

## Types with the `store` Ability

All native types (except for references) in Move have the `store` ability. This includes:

- bool
- unsigned integers
- [vector](../../../../references/framework/move-stdlib/vector.mdx)
- [address](../../../../references/framework/move-stdlib/address.mdx)

All of the types defined in the standard library have the `store` ability as well. This includes:

- [Option](../../../../references/framework/move-stdlib/option.mdx)
- [String](../../../../references/framework/move-stdlib/string.mdx)
- [TypeName](../../../../references/framework/move-stdlib/type_name.mdx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Custom Types with Struct

Move's type system offers the ability to define custom types. User defined types can be custom
tailored to the specific needs of the application. Not just on the data level, but also in its
behavior. In this section we introduce the struct definition and how to use it.

## Struct

To define a custom type, you can use the `struct` keyword followed by the name of the type. After
the name, you can define the fields of the struct. Each field is defined with the
`field_name: field_type` syntax. Field definitions must be separated by commas. The fields can be of
any type, including other structs.

:::info
Move does not support recursive structs, meaning a struct cannot contain itself as a field.
:::

```move file=<rootDir>/docs/examples/move/move-overview/struct.move#L10-L28
```


In the example above, we define a `Record` struct with five fields. The `title` field is of type
`String`, the `artist` field is of type `Artist`, the `year` field is of type `u16`, the `is_debut`
field is of type `bool`, and the `edition` field is of type `Option<u16>`. The `edition` field is of
type `Option<u16>` to represent that the edition is optional.

Structs are private by default, meaning they cannot be imported and used outside of the module they
are defined in. Their fields are also private and can't be accessed from outside the module. See
[visibility](../visibility.mdx) for more information on different visibility modifiers.

:::info
Fields of a struct are private and can only be accessed by the module defining the struct. Reading
and writing the fields of a struct in other modules is only possible if the module defining the
struct provides public functions to access the fields.
:::

## Create and use an instance

We described how struct _definition_ works. Now let's see how to initialize a struct and use it. A
struct can be initialized using the `struct_name { field1: value1, field2: value2, ... }` syntax.
The fields can be initialized in any order, and all of the fields must be set.

```move file=<rootDir>/docs/examples/move/move-overview/struct.move#L34-L36
```

In the example above, we create an instance of the `Artist` struct and set the `name` field to a
string "The Beatles".

To access the fields of a struct, you can use the `.` operator followed by the field name.

```move file=<rootDir>/docs/examples/move/move-overview/struct.move#L40-L50
```

Only module defining the struct can access its fields (both mutably and immutably). So the above
code should be in the same module as the `Artist` struct.


## Unpacking a struct

Structs are non-discardable by default, meaning that the initiated struct value must be used: either
stored or _unpacked_. Unpacking a struct means deconstructing it into its fields. This is done using
the `let` keyword followed by the struct name and the field names.

```move file=<rootDir>/docs/examples/move/move-overview/struct.move#L54-L56
```

In the example above we unpack the `Artist` struct and create a new variable `name` with the value
of the `name` field. Because the variable is not used, the compiler will raise a warning. To
suppress the warning, you can use the underscore `_` to indicate that the variable is intentionally
unused.

```move file=<rootDir>/docs/examples/move/move-overview/struct.move#L64-L65
```
Loading

0 comments on commit 67c08d6

Please sign in to comment.