From e9e0972c27dc38b8106a78fb09ab4ae542942a57 Mon Sep 17 00:00:00 2001 From: Damir Shamanaev Date: Mon, 15 Apr 2024 14:52:04 +0200 Subject: [PATCH] chore: formatting (#51) --- book/src/404.md | 10 +- book/src/before-we-begin/README.md | 5 +- book/src/before-we-begin/ide-support.md | 26 ++-- book/src/before-we-begin/install-sui.md | 3 +- book/src/before-we-begin/move-2024.md | 5 +- book/src/concepts/README.md | 6 +- book/src/concepts/manifest.md | 41 ++++-- book/src/concepts/packages.md | 23 +++- book/src/concepts/what-is-a-transaction.md | 31 +++-- book/src/concepts/what-is-an-account.md | 18 ++- book/src/guides/2024-migration-guide.md | 57 +++++--- book/src/guides/README.md | 4 +- book/src/guides/better-error-handling.md | 36 ++++-- book/src/guides/building-against-limits.md | 35 +++-- book/src/guides/coding-conventions.md | 3 +- book/src/guides/open-sourcing-libraries.md | 9 +- book/src/guides/upgradeability-practices.md | 18 ++- book/src/move-basics/README.md | 7 +- .../src/move-basics/abilities-introduction.md | 40 ++++-- book/src/move-basics/address.md | 13 +- book/src/move-basics/assert-and-abort.md | 25 +++- book/src/move-basics/comments.md | 20 ++- book/src/move-basics/constants.md | 21 ++- book/src/move-basics/control-flow.md | 70 +++++++--- book/src/move-basics/copy-ability.md | 21 ++- book/src/move-basics/drop-ability.md | 17 ++- book/src/move-basics/expression.md | 28 +++- book/src/move-basics/function.md | 35 +++-- book/src/move-basics/generics.md | 63 ++++++--- book/src/move-basics/importing-modules.md | 50 +++++-- book/src/move-basics/module.md | 21 ++- book/src/move-basics/option.md | 30 ++++- book/src/move-basics/ownership-and-scope.md | 32 +++-- book/src/move-basics/primitive-types.md | 31 +++-- book/src/move-basics/references.md | 41 ++++-- book/src/move-basics/standard-library.md | 19 ++- book/src/move-basics/string.md | 25 +++- book/src/move-basics/struct-methods.md | 30 ++++- book/src/move-basics/struct.md | 41 ++++-- book/src/move-basics/testing.md | 32 +++-- book/src/move-basics/type-reflection.md | 15 ++- book/src/move-basics/vector.md | 20 ++- book/src/move-basics/visibility.md | 15 ++- book/src/object/README.md | 11 +- book/src/object/digital-assets.md | 43 ++++-- book/src/object/evolution-of-move.md | 22 +++- book/src/object/fast-path-and-consensus.md | 41 ++++-- book/src/object/object-model.md | 30 ++++- book/src/object/ownership.md | 56 ++++++-- book/src/programmability/README.md | 9 +- book/src/programmability/abstract-class.md | 41 ------ book/src/programmability/bcs.md | 11 +- book/src/programmability/capability.md | 47 +++++-- book/src/programmability/collections.md | 50 +++++-- book/src/programmability/display.md | 62 ++++++--- book/src/programmability/dynamic-fields.md | 114 ++++++++++++---- .../programmability/dynamic-object-fields.md | 48 +++++-- book/src/programmability/epoch-and-time.md | 25 +++- book/src/programmability/events.md | 21 ++- book/src/programmability/fast-path.md | 30 ++++- .../src/programmability/module-initializer.md | 35 +++-- book/src/programmability/one-time-witness.md | 26 +++- book/src/programmability/publisher.md | 39 ++++-- book/src/programmability/sui-framework.md | 14 +- .../programmability/transaction-context.md | 26 +++- book/src/programmability/witness-pattern.md | 3 - book/src/storage/README.md | 5 +- book/src/storage/key-ability.md | 29 ++++- book/src/storage/storage-functions.md | 122 +++++++++++++----- book/src/storage/store-ability.md | 14 +- book/src/storage/transfer-restrictions.md | 28 ++-- book/src/storage/transfer-to-object.md | 3 +- book/src/storage/uid-and-id.md | 46 +++++-- 73 files changed, 1581 insertions(+), 562 deletions(-) delete mode 100644 book/src/programmability/abstract-class.md delete mode 100644 book/src/programmability/witness-pattern.md diff --git a/book/src/404.md b/book/src/404.md index 94b1d6f0..e7cfc78a 100644 --- a/book/src/404.md +++ b/book/src/404.md @@ -4,8 +4,10 @@ You're looking for a page that doesn't exist, or has been moved. Please check th > Here are the links you may be looking for: > ->- [The Move Book](/) - the main page of the book ->- [The Move Reference](/reference) - the Move Language Reference -> +> - [The Move Book](/) - the main page of the book +> - [The Move Reference](/reference) - the Move Language Reference -Recently we updated the structure of the book and some pages have been moved or renamed. If you're looking for the old version of the book, please, see the ["archive" branch in the repository](https://github.com/MystenLabs/move-book/tree/archive). Though we highly recommend using [the latest version of the book](/). +Recently we updated the structure of the book and some pages have been moved or renamed. If you're +looking for the old version of the book, please, see the +["archive" branch in the repository](https://github.com/MystenLabs/move-book/tree/archive). Though +we highly recommend using [the latest version of the book](/). diff --git a/book/src/before-we-begin/README.md b/book/src/before-we-begin/README.md index 318e65e6..ff0596b6 100644 --- a/book/src/before-we-begin/README.md +++ b/book/src/before-we-begin/README.md @@ -1,3 +1,6 @@ # Before we begin -Move requires an environment to run and develop applications, and in this small chapter we will cover the prerequisites for the Move language: how to set up your IDE, how to install the compiler and what is Move 2024. If you are already familiar with these topics or have a CLI installed, you can skip this chapter and proceed to [the next one](../your-first-move/hello-world.md). +Move requires an environment to run and develop applications, and in this small chapter we will +cover the prerequisites for the Move language: how to set up your IDE, how to install the compiler +and what is Move 2024. If you are already familiar with these topics or have a CLI installed, you +can skip this chapter and proceed to [the next one](../your-first-move/hello-world.md). diff --git a/book/src/before-we-begin/ide-support.md b/book/src/before-we-begin/ide-support.md index d4e9e6d5..f5d0cfc6 100644 --- a/book/src/before-we-begin/ide-support.md +++ b/book/src/before-we-begin/ide-support.md @@ -1,28 +1,38 @@ # Set up your IDE -There are two most popular IDEs for Move development: VSCode and IntelliJ IDEA. Both of them provide basic features like syntax highlighting and error messages, though they differ in their additional features. Whatever IDE you choose, you'll need to use the terminal to run the [Move CLI](./install-sui.md). +There are two most popular IDEs for Move development: VSCode and IntelliJ IDEA. Both of them provide +basic features like syntax highlighting and error messages, though they differ in their additional +features. Whatever IDE you choose, you'll need to use the terminal to run the +[Move CLI](./install-sui.md). -> **IntelliJ Plugin does not support Move 2024 edition fully, some syntax won't get highlighted and not supported.** +> **IntelliJ Plugin does not support Move 2024 edition fully, some syntax won't get highlighted and +> not supported.** ## VSCode - [VSCode](https://code.visualstudio.com/) is a free and open source IDE from Microsoft. -- [Move Analyzer](https://marketplace.visualstudio.com/items?itemName=move.move-analyzer) is a language server extension for Move maintained by [MystenLabs](https://mystenlabs.com). -- [Move Syntax](https://marketplace.visualstudio.com/items?itemName=damirka.move-syntax) a simple syntax highlighting extension for Move by [Damir Shamanaev](https://github.com/damirka/). +- [Move Analyzer](https://marketplace.visualstudio.com/items?itemName=move.move-analyzer) is a + language server extension for Move maintained by [MystenLabs](https://mystenlabs.com). +- [Move Syntax](https://marketplace.visualstudio.com/items?itemName=damirka.move-syntax) a simple + syntax highlighting extension for Move by [Damir Shamanaev](https://github.com/damirka/). ## IntelliJ IDEA - [IntelliJ IDEA](https://www.jetbrains.com/idea/) is a commercial IDE from JetBrains. -- [Move Language Plugin](https://plugins.jetbrains.com/plugin/14721-move-language) provides a Move language extension for IntelliJ IDEA by [Pontem Network](https://pontem.network/). +- [Move Language Plugin](https://plugins.jetbrains.com/plugin/14721-move-language) provides a Move + language extension for IntelliJ IDEA by [Pontem Network](https://pontem.network/). ## Emacs - [Emacs](https://www.gnu.org/software/emacs/) is a free and open source text editor. -- [move-mode](https://github.com/amnn/move-mode) is a Move mode for Emacs by [Ashok Menon](https://github.com/amnn). +- [move-mode](https://github.com/amnn/move-mode) is a Move mode for Emacs by + [Ashok Menon](https://github.com/amnn). ## Github Codespaces -The Web-based IDE from Github can be run right in the browser and provides almost a full-featured VSCode experience. +The Web-based IDE from Github can be run right in the browser and provides almost a full-featured +VSCode experience. - [Github Codespaces](https://github.com/features/codespaces) -- [Move Syntax](https://marketplace.visualstudio.com/items?itemName=damirka.move-syntax) is also available in the extensions marketplace. +- [Move Syntax](https://marketplace.visualstudio.com/items?itemName=damirka.move-syntax) is also + available in the extensions marketplace. diff --git a/book/src/before-we-begin/install-sui.md b/book/src/before-we-begin/install-sui.md index e23a3207..0f3583da 100644 --- a/book/src/before-we-begin/install-sui.md +++ b/book/src/before-we-begin/install-sui.md @@ -20,7 +20,8 @@ brew install sui ## Install using Chocolatey (Windows) -You can install Sui using the [Chocolatey](https://chocolatey.org/install) package manager for Windows. +You can install Sui using the [Chocolatey](https://chocolatey.org/install) package manager for +Windows. ```bash choco install sui diff --git a/book/src/before-we-begin/move-2024.md b/book/src/before-we-begin/move-2024.md index 6fb7192c..5ee2f4ea 100644 --- a/book/src/before-we-begin/move-2024.md +++ b/book/src/before-we-begin/move-2024.md @@ -1,5 +1,8 @@ # Move 2024 -Move 2024 is the new edition of the Move language maintained by Mysten Labs. All of the examples in this book are written in Move 2024. If you're used to the pre-2024 version of Move, please, refer to the [Move 2024 Migration Guide](./../guides/2024-migration-guide.md) to learn about the changes and improvements in the new edition. +Move 2024 is the new edition of the Move language maintained by Mysten Labs. All of the examples in +this book are written in Move 2024. If you're used to the pre-2024 version of Move, please, refer to +the [Move 2024 Migration Guide](./../guides/2024-migration-guide.md) to learn about the changes and +improvements in the new edition. diff --git a/book/src/concepts/README.md b/book/src/concepts/README.md index 978c6238..19da4d7c 100644 --- a/book/src/concepts/README.md +++ b/book/src/concepts/README.md @@ -1,3 +1,7 @@ # Concepts -In this chapter you will learn about the basic concepts of Sui and Move. You will learn what is a package, how to interact with it, what is an account and a transaction, and how data is stored on Sui. While this chapter is not a complete reference, and you should refer to the [Sui Documentation](https://docs.sui.io) for that, it will give you a good understanding of the basic concepts required to write Move programs on Sui. +In this chapter you will learn about the basic concepts of Sui and Move. You will learn what is a +package, how to interact with it, what is an account and a transaction, and how data is stored on +Sui. While this chapter is not a complete reference, and you should refer to the +[Sui Documentation](https://docs.sui.io) for that, it will give you a good understanding of the +basic concepts required to write Move programs on Sui. diff --git a/book/src/concepts/manifest.md b/book/src/concepts/manifest.md index c32546ce..2b75af68 100644 --- a/book/src/concepts/manifest.md +++ b/book/src/concepts/manifest.md @@ -1,6 +1,8 @@ # Package Manifest -The `Move.toml` is a manifest file that describes the [package](./packages.md) and its dependencies. It is written in [TOML](https://toml.io/en/) format and contains multiple sections, the most important of which are `[package]`, `[dependencies]` and `[addresses]`. +The `Move.toml` is a manifest file that describes the [package](./packages.md) and its dependencies. +It is written in [TOML](https://toml.io/en/) format and contains multiple sections, the most +important of which are `[package]`, `[dependencies]` and `[addresses]`. ```toml [package] @@ -23,7 +25,9 @@ alice = "0xB0B" ### Package -The `[package]` section is used to describe the package. None of the fields in this section are published on chain, but they are used in tooling and release management; they also specify the Move edition for the compiler. +The `[package]` section is used to describe the package. None of the fields in this section are +published on chain, but they are used in tooling and release management; they also specify the Move +edition for the compiler. - `name` - the name of the package when it is imported; - `version` - the version of the package, can be used in release management; @@ -33,7 +37,10 @@ The `[package]` section is used to describe the package. None of the fields in t ### Dependencies -The `[dependencies]` section is used to specify the dependencies of the project. Each dependency is specified as a key-value pair, where the key is the name of the dependency, and the value is the dependency specification. The dependency specification can be a git repository URL or a path to the local directory. +The `[dependencies]` section is used to specify the dependencies of the project. Each dependency is +specified as a key-value pair, where the key is the name of the dependency, and the value is the +dependency specification. The dependency specification can be a git repository URL or a path to the +local directory. ```toml # git repository @@ -43,11 +50,17 @@ Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-fram MyPackage = { local = "../my-package" } ``` -Packages also import addresses from other packages. For example, the Sui dependency adds the `std` and `sui` addresses to the project. These addresses can be used in the code as aliases for the addresses. +Packages also import addresses from other packages. For example, the Sui dependency adds the `std` +and `sui` addresses to the project. These addresses can be used in the code as aliases for the +addresses. ### Resolving version conflicts with override -Sometimes dependencies have conflicting versions of the same package. For example, if you have two dependencies that use different versions of the Sui package, you can override the dependency in the `[dependencies]` section. To do so, add the `override` field to the dependency. The version of the dependency specified in the `[dependencies]` section will be used instead of the one specified in the dependency itself. +Sometimes dependencies have conflicting versions of the same package. For example, if you have two +dependencies that use different versions of the Sui package, you can override the dependency in the +`[dependencies]` section. To do so, add the `override` field to the dependency. The version of the +dependency specified in the `[dependencies]` section will be used instead of the one specified in +the dependency itself. ```toml [dependencies] @@ -56,19 +69,29 @@ Sui = { override = true, git = "https://github.com/MystenLabs/sui.git", subdir = ### Dev-dependencies -It is possible to add `[dev-dependencies]` section to the manifest. It is used to override dependencies in the dev and test modes. For example, if you want to use a different version of the Sui package in the dev mode, you can add a custom dependency specification to the `[dev-dependencies]` section. +It is possible to add `[dev-dependencies]` section to the manifest. It is used to override +dependencies in the dev and test modes. For example, if you want to use a different version of the +Sui package in the dev mode, you can add a custom dependency specification to the +`[dev-dependencies]` section. ### Addresses -The `[addresses]` section is used to add aliases for the addresses. Any address can be specified in this section, and then used in the code as an alias. For example, if you add `alice = "0xA11CE"` to this section, you can use `alice` as `0xA11CE` in the code. +The `[addresses]` section is used to add aliases for the addresses. Any address can be specified in +this section, and then used in the code as an alias. For example, if you add `alice = "0xA11CE"` to +this section, you can use `alice` as `0xA11CE` in the code. ### Dev-addresses -The `[dev-addresses]` section is the same as `[addresses]`, but only works for the test and dev modes. Important to note that it is impossible to introduce new aliases in this section, only override the existing ones. So in the example above, if you add `alice = "0xB0B"` to this section, the `alice` address will be `0xB0B` in the test and dev modes, and `0xA11CE` in the regular build. +The `[dev-addresses]` section is the same as `[addresses]`, but only works for the test and dev +modes. Important to note that it is impossible to introduce new aliases in this section, only +override the existing ones. So in the example above, if you add `alice = "0xB0B"` to this section, +the `alice` address will be `0xB0B` in the test and dev modes, and `0xA11CE` in the regular build. ## TOML styles -The TOML format supports two styles for tables: inline and multiline. The examples above are using the inline style, but it is also possible to use the multiline style. You wouldn't want to use it for the `[package]` section, but it can be useful for the dependencies. +The TOML format supports two styles for tables: inline and multiline. The examples above are using +the inline style, but it is also possible to use the multiline style. You wouldn't want to use it +for the `[package]` section, but it can be useful for the dependencies. ```toml # Inline style diff --git a/book/src/concepts/packages.md b/book/src/concepts/packages.md index 49e3b787..af22012c 100644 --- a/book/src/concepts/packages.md +++ b/book/src/concepts/packages.md @@ -16,10 +16,14 @@ --> -Move is a language for writing smart contracts - programs that stored and run on the blockchain. A single program is organized into a package. A package is published on the blockchain and is identified by an [address](./address.md). A published package can be interacted with by sending [transactions](./what-is-a-transaction.md) calling its functions. It can also act as a dependency for other packages. +Move is a language for writing smart contracts - programs that stored and run on the blockchain. A +single program is organized into a package. A package is published on the blockchain and is +identified by an [address](./address.md). A published package can be interacted with by sending +[transactions](./what-is-a-transaction.md) calling its functions. It can also act as a dependency +for other packages. -> To create a new package, use the `sui move new` command. -> To learn more about the command, run `sui move new --help`. +> To create a new package, use the `sui move new` command. To learn more about the command, run +> `sui move new --help`. Package consists of modules - separate scopes that contain functions, types, and other items. @@ -35,7 +39,9 @@ package 0x... ## Package Structure -Locally, a package is a directory with a `Move.toml` file and a `sources` directory. The `Move.toml` file - called the "package manifest" - contains metadata about the package, and the `sources` directory contains the source code for the modules. Package usually looks like this: +Locally, a package is a directory with a `Move.toml` file and a `sources` directory. The `Move.toml` +file - called the "package manifest" - contains metadata about the package, and the `sources` +directory contains the source code for the modules. Package usually looks like this: ``` sources/ @@ -49,11 +55,16 @@ examples/ Move.toml ``` -The `tests` directory is optional and contains tests for the package. Code placed into the `tests` directory is not published on-chain and is only availably in tests. The `examples` directory can be used for code examples, and is also not published on-chain. +The `tests` directory is optional and contains tests for the package. Code placed into the `tests` +directory is not published on-chain and is only availably in tests. The `examples` directory can be +used for code examples, and is also not published on-chain. ## Published Package -During development, package doesn't have an address and it needs to be set to `0x0`. Once a package is published, it gets a single unique [address](./address.md) on the blockchain containing its modules' bytecode. A published package becomes _immutable_ and can be interacted with by sending transactions. +During development, package doesn't have an address and it needs to be set to `0x0`. Once a package +is published, it gets a single unique [address](./address.md) on the blockchain containing its +modules' bytecode. A published package becomes _immutable_ and can be interacted with by sending +transactions. ``` 0x... diff --git a/book/src/concepts/what-is-a-transaction.md b/book/src/concepts/what-is-a-transaction.md index 666141cf..0577d1cf 100644 --- a/book/src/concepts/what-is-a-transaction.md +++ b/book/src/concepts/what-is-a-transaction.md @@ -1,6 +1,9 @@ # Transaction -Transaction is a fundamental concept in the blockchain world. It is a way to interact with a blockchain. Transactions are used to change the state of the blockchain, and they are the only way to do so. In Move, transactions are used to call functions in a package, deploy new packages, and upgrade existing ones. +Transaction is a fundamental concept in the blockchain world. It is a way to interact with a +blockchain. Transactions are used to change the state of the blockchain, and they are the only way +to do so. In Move, transactions are used to call functions in a package, deploy new packages, and +upgrade existing ones. -An account is a way to identify a user. An account is generated from a private key, and is identified by an address. An account can own objects, and can send transactions. Every transaction has a sender, and the sender is identified by an [address](./address.md). +An account is a way to identify a user. An account is generated from a private key, and is +identified by an address. An account can own objects, and can send transactions. Every transaction +has a sender, and the sender is identified by an [address](./address.md). -Sui supports multiple cryptographic algorithms for account generation. The two supported curves are ed25519, secp256k1, and there is also a special way of generating an account - zklogin. The cryptographic agility - the unique feature of Sui - allows for flexibility in the account generation. +Sui supports multiple cryptographic algorithms for account generation. The two supported curves are +ed25519, secp256k1, and there is also a special way of generating an account - zklogin. The +cryptographic agility - the unique feature of Sui - allows for flexibility in the account +generation. ## Further Reading -- [Cryptography in Sui](https://blog.sui.io/wallet-cryptography-specifications/) in the [Sui Blog](https://blog.sui.io) -- [Keys and Addresses](https://docs.sui.io/concepts/cryptography/transaction-auth/keys-addresses) in the [Sui Docs](https://docs.sui.io) -- [Signatures](https://docs.sui.io/concepts/cryptography/transaction-auth/signatures) in the [Sui Docs](https://docs.sui.io) +- [Cryptography in Sui](https://blog.sui.io/wallet-cryptography-specifications/) in the + [Sui Blog](https://blog.sui.io) +- [Keys and Addresses](https://docs.sui.io/concepts/cryptography/transaction-auth/keys-addresses) in + the [Sui Docs](https://docs.sui.io) +- [Signatures](https://docs.sui.io/concepts/cryptography/transaction-auth/signatures) in the + [Sui Docs](https://docs.sui.io) diff --git a/book/src/guides/2024-migration-guide.md b/book/src/guides/2024-migration-guide.md index c246bfee..d84a802a 100644 --- a/book/src/guides/2024-migration-guide.md +++ b/book/src/guides/2024-migration-guide.md @@ -1,12 +1,18 @@ # Move 2024 Migration Guide -Move 2024 is the new edition of the Move language that is maintained by Mysten Labs. This guide is intended to help you understand the differences between the 2024 edition and the previous version of the Move language. +Move 2024 is the new edition of the Move language that is maintained by Mysten Labs. This guide is +intended to help you understand the differences between the 2024 edition and the previous version of +the Move language. -> This guide provides a high-level overview of the changes in the new edition. For a more detailed and exhaustive list of changes, refer to the [Sui Documentation](https://docs.sui.io/guides/developer/advanced/move-2024-migration). +> This guide provides a high-level overview of the changes in the new edition. For a more detailed +> and exhaustive list of changes, refer to the +> [Sui Documentation](https://docs.sui.io/guides/developer/advanced/move-2024-migration). ## Using the New Edition -To use the new edition, you need to specify the edition in the `move` file. The edition is specified in the `move` file using the `edition` keyword. Currently, the only available edition is `2024.beta`. +To use the new edition, you need to specify the edition in the `move` file. The edition is specified +in the `move` file using the `edition` keyword. Currently, the only available edition is +`2024.beta`. ```ini edition = "2024.beta"; @@ -14,19 +20,23 @@ edition = "2024.beta"; ## Migration Tool -The Move CLI has a migration tool that updates the code to the new edition. To use the migration tool, run the following command: +The Move CLI has a migration tool that updates the code to the new edition. To use the migration +tool, run the following command: ```bash $ sui move migrate ``` -The migration tool will update the code to use the `let mut` syntax, the new `public` modifier for strucs, and the `public(package)` function visibility instead of `friend` declarations. +The migration tool will update the code to use the `let mut` syntax, the new `public` modifier for +strucs, and the `public(package)` function visibility instead of `friend` declarations. ## Mutable bindings with `let mut` -Move 2024 introduces `let mut` syntax to declare mutable variables. The `let mut` syntax is used to declare a mutable variable that can be changed after it is declared. +Move 2024 introduces `let mut` syntax to declare mutable variables. The `let mut` syntax is used to +declare a mutable variable that can be changed after it is declared. -> `let mut` declaration is now required for mutable variables. Compiler will emit an error if you try to reassign a variable without the `mut` keyword. +> `let mut` declaration is now required for mutable variables. Compiler will emit an error if you +> try to reassign a variable without the `mut` keyword. ```move // Move 2020 @@ -38,7 +48,8 @@ let mut x: u64 = 10; x = 20; ``` -Additionally, the `mut` keyword is used in tuple destructuring and function arguments to declare mutable variables. +Additionally, the `mut` keyword is used in tuple destructuring and function arguments to declare +mutable variables. ```move // takes by value and mutates @@ -63,7 +74,8 @@ fun unpack() { ## Friends are Deprecated -In Move 2024, the `friend` keyword is deprecated. Instead, you can use the `public(package)` visibility modifier to make functions visible to other modules in the same package. +In Move 2024, the `friend` keyword is deprecated. Instead, you can use the `public(package)` +visibility modifier to make functions visible to other modules in the same package. ```move // Move 2020 @@ -76,7 +88,8 @@ public(package) fun protected_function_2024() {} ## Struct Visibility -In Move 2024, structs get a visibility modifier. Currently, the only available visibility modifier is `public`. +In Move 2024, structs get a visibility modifier. Currently, the only available visibility modifier +is `public`. ```move // Move 2020 @@ -88,9 +101,13 @@ public struct Book {} ## Method Syntax -In the new edition, functions which have a struct as the first argument are associated with the struct. This means that the function can be called using the dot notation. Methods defined in the same module with the type are automatically exported. +In the new edition, functions which have a struct as the first argument are associated with the +struct. This means that the function can be called using the dot notation. Methods defined in the +same module with the type are automatically exported. -> Methods are automatically exported if the type is defined in the same module as the method. It is impossible to export methods for types defined in other modules. However, you can create [custom aliases](#method-aliases) for methods in the module scope. +> Methods are automatically exported if the type is defined in the same module as the method. It is +> impossible to export methods for types defined in other modules. However, you can create +> [custom aliases](#method-aliases) for methods in the module scope. ```move public fun count(c: &Counter): u64 { /* ... */ } @@ -106,7 +123,8 @@ fun use_counter() { ## Methods for Built-in Types -In Move 2024, some of the native and standard types received associated methods. For example, the `vector` type has a `to_string` method that converts the vector into a UTF8 string. +In Move 2024, some of the native and standard types received associated methods. For example, the +`vector` type has a `to_string` method that converts the vector into a UTF8 string. ```move fun aliases() { @@ -119,11 +137,14 @@ fun aliases() { } ``` -For the full list of built-in aliases, refer to the [Standard Library](../move-basics/standard-library.md#source-code) and [Sui Framework](../programmability/sui-framework.md#source-code) source code. +For the full list of built-in aliases, refer to the +[Standard Library](../move-basics/standard-library.md#source-code) and +[Sui Framework](../programmability/sui-framework.md#source-code) source code. ## Borrowing Operator -Some of the built-in types support borrowing operators. The borrowing operator is used to get a reference to the element at the specified index. The borrowing operator is defined as `[]`. +Some of the built-in types support borrowing operators. The borrowing operator is used to get a +reference to the element at the specified index. The borrowing operator is defined as `[]`. ```move fun play_vec() { @@ -144,7 +165,8 @@ Types that support the borrowing operator are: - `sui::object_bag::ObjectBag` - `sui::linked_table::LinkedTable` -To implement the borrowing operator for a custom type, you need to add a `#[syntax(index)]` attribute to the methods. +To implement the borrowing operator for a custom type, you need to add a `#[syntax(index)]` +attribute to the methods. ```move #[syntax(index)] @@ -156,7 +178,8 @@ public fun borrow_mut(c: &mut List, key: String): &mut T { /* ... */ } ## Method Aliases -In Move 2024, methods can be associated with types. The alias can be defined for any type locally to the module; or publicly, if the type is defined in the same module. +In Move 2024, methods can be associated with types. The alias can be defined for any type locally to +the module; or publicly, if the type is defined in the same module. ```move // my_module.move diff --git a/book/src/guides/README.md b/book/src/guides/README.md index 2b542229..e90c75b1 100644 --- a/book/src/guides/README.md +++ b/book/src/guides/README.md @@ -1,3 +1,5 @@ # Guides -This section contains a collection of guides that cover various aspects of programming on Sui. They are intended to provide a deeper understanding of Sui blockchain and Move language, while also aiming at practical challenges and solutions. +This section contains a collection of guides that cover various aspects of programming on Sui. They +are intended to provide a deeper understanding of Sui blockchain and Move language, while also +aiming at practical challenges and solutions. diff --git a/book/src/guides/better-error-handling.md b/book/src/guides/better-error-handling.md index 0e476d7f..d59230db 100644 --- a/book/src/guides/better-error-handling.md +++ b/book/src/guides/better-error-handling.md @@ -1,6 +1,11 @@ # Better error handling -Whenever execution encounters an abort, transaction fails and abort code is returned to the caller. Move VM returns the module name that aborted the transaction and the abort code. This behavior is not fully transparent to the caller of the transaction, especially when a single function contains multiple calls to the same function which may abort. In this case, the caller will not know which call aborted the transaction, and it will be hard to debug the issue or provide meaningful error message to the user. +Whenever execution encounters an abort, transaction fails and abort code is returned to the caller. +Move VM returns the module name that aborted the transaction and the abort code. This behavior is +not fully transparent to the caller of the transaction, especially when a single function contains +multiple calls to the same function which may abort. In this case, the caller will not know which +call aborted the transaction, and it will be hard to debug the issue or provide meaningful error +message to the user. ```move module book::module_a { @@ -16,11 +21,17 @@ module book::module_a { } ``` -The example above illustrates the case when a single function contains multiple calls which may abort. If the caller of the `do_something` function receives an abort code `0`, it will be hard to understand which call to `module_b::get_field` aborted the transaction. To address this problem, there are common patterns that can be used to improve error handling. +The example above illustrates the case when a single function contains multiple calls which may +abort. If the caller of the `do_something` function receives an abort code `0`, it will be hard to +understand which call to `module_b::get_field` aborted the transaction. To address this problem, +there are common patterns that can be used to improve error handling. ## Rule 1: Handle all possible scenarios -It is considered a good practice to provide a safe "check" function that returns a boolean value indicating whether an operation can be performed safely. If the `module_b` provides a function `has_field` that returns a boolean value indicating whether a field exists, the `do_something` function can be rewritten as follows: +It is considered a good practice to provide a safe "check" function that returns a boolean value +indicating whether an operation can be performed safely. If the `module_b` provides a function +`has_field` that returns a boolean value indicating whether a field exists, the `do_something` +function can be rewritten as follows: ```move module book::module_a { @@ -41,11 +52,14 @@ module book::module_a { } ``` -By adding custom checks before each call to `module_b::get_field`, the developer of the `module_a` takes control over the error handling. And it allows implementing the second rule. +By adding custom checks before each call to `module_b::get_field`, the developer of the `module_a` +takes control over the error handling. And it allows implementing the second rule. ## Rule 2: Abort with different codes -The second trick, once the abort codes are handled by the caller module, is to use different abort codes for different scenarios. This way, the caller module can provide a meaningful error message to the user. The `module_a` can be rewritten as follows: +The second trick, once the abort codes are handled by the caller module, is to use different abort +codes for different scenarios. This way, the caller module can provide a meaningful error message to +the user. The `module_a` can be rewritten as follows: ```move module book::module_a { @@ -68,11 +82,16 @@ module book::module_a { } ``` -Now, the caller module can provide a meaningful error message to the user. If the caller receives an abort code `0`, it can be translated to "Field 1 does not exist". If the caller receives an abort code `1`, it can be translated to "Field 2 does not exist". And so on. +Now, the caller module can provide a meaningful error message to the user. If the caller receives an +abort code `0`, it can be translated to "Field 1 does not exist". If the caller receives an abort +code `1`, it can be translated to "Field 2 does not exist". And so on. ## Rule 3: Return bool instead of assert -A developer is often tempted to add a public function that would assert all the conditions and abort the execution. However, it is a better practice to create a function that returns a boolean value instead. This way, the caller module can handle the error and provide a meaningful error message to the user. +A developer is often tempted to add a public function that would assert all the conditions and abort +the execution. However, it is a better practice to create a function that returns a boolean value +instead. This way, the caller module can handle the error and provide a meaningful error message to +the user. ```move module book::some_app_assert { @@ -124,4 +143,5 @@ module book::some_app { } ``` -Utilizing these three rules will make the error handling more transparent to the caller of the transaction, and it will allow other developers to use custom abort codes in their modules. +Utilizing these three rules will make the error handling more transparent to the caller of the +transaction, and it will allow other developers to use custom abort codes in their modules. diff --git a/book/src/guides/building-against-limits.md b/book/src/guides/building-against-limits.md index a607fe67..c99e5a3b 100644 --- a/book/src/guides/building-against-limits.md +++ b/book/src/guides/building-against-limits.md @@ -1,29 +1,48 @@ # Building against Limits -To guarantee the safety and security of the network, Sui has certain limits and restrictions. These limits are in place to prevent abuse and to ensure that the network remains stable and efficient. This guide provides an overview of these limits and restrictions, and how to build your application to work within them. +To guarantee the safety and security of the network, Sui has certain limits and restrictions. These +limits are in place to prevent abuse and to ensure that the network remains stable and efficient. +This guide provides an overview of these limits and restrictions, and how to build your application +to work within them. -The limits are defined in the protocol configuration and are enforced by the network. If any of the limits are exceeded, the transaction will either be rejected or aborted. The limits, being a part of the protocol, can only be changed through a network upgrade. +The limits are defined in the protocol configuration and are enforced by the network. If any of the +limits are exceeded, the transaction will either be rejected or aborted. The limits, being a part of +the protocol, can only be changed through a network upgrade. ## Transaction Size -The size of a transaction is limited to 128KB. This includes the size of the transaction payload, the size of the transaction signature, and the size of the transaction metadata. If a transaction exceeds this limit, it will be rejected by the network. +The size of a transaction is limited to 128KB. This includes the size of the transaction payload, +the size of the transaction signature, and the size of the transaction metadata. If a transaction +exceeds this limit, it will be rejected by the network. ## Object Size -The size of an object is limited to 256KB. This includes the size of the object data. If an object exceeds this limit, it will be rejected by the network. While a single object cannot bypass this limit, for more extensive storage options, one could use a combination of a base object with other attached to it using dynamic fields (eg Bag). +The size of an object is limited to 256KB. This includes the size of the object data. If an object +exceeds this limit, it will be rejected by the network. While a single object cannot bypass this +limit, for more extensive storage options, one could use a combination of a base object with other +attached to it using dynamic fields (eg Bag). ## Single Pure Argument Size -The size of a single pure argument is limited to 16KB. A transaction argument bigger than this limit will result in execution failure. So in order to create a vector of more than ~500 addresses (given that a single address is 32 bytes), it needs to be joined dynamically either in Transaction Block or in a Move function. Standard functions like `vector::append()` can join two vectors of ~16KB resulting in a ~32KB of data as a single value. +The size of a single pure argument is limited to 16KB. A transaction argument bigger than this limit +will result in execution failure. So in order to create a vector of more than ~500 addresses (given +that a single address is 32 bytes), it needs to be joined dynamically either in Transaction Block or +in a Move function. Standard functions like `vector::append()` can join two vectors of ~16KB +resulting in a ~32KB of data as a single value. ## Maximum Number of Objects created -The maximum number of objects that can be created in a single transaction is 2048. If a transaction attempts to create more than 2048 objects, it will be rejected by the network. This also affects [dynamic fields](./../programmability/dynamic-fields.md), as both the key and the value are objects. So the maximum number of dynamic fields that can be created in a single transaction is 1024. +The maximum number of objects that can be created in a single transaction is 2048. If a transaction +attempts to create more than 2048 objects, it will be rejected by the network. This also affects +[dynamic fields](./../programmability/dynamic-fields.md), as both the key and the value are objects. +So the maximum number of dynamic fields that can be created in a single transaction is 1024. ## Maximum Number of Dynamic Fields created -The maximum number of dynamic fields that can be created in a single object is 1024. If an object attempts to create more than 1024 dynamic fields, it will be rejected by the network. +The maximum number of dynamic fields that can be created in a single object is 1024. If an object +attempts to create more than 1024 dynamic fields, it will be rejected by the network. ## Maximum Number of Events -The maximum number of events that can be emitted in a single transaction is 1024. If a transaction attempts to emit more than 1024 events, it will be aborted. +The maximum number of events that can be emitted in a single transaction is 1024. If a transaction +attempts to emit more than 1024 events, it will be aborted. diff --git a/book/src/guides/coding-conventions.md b/book/src/guides/coding-conventions.md index 3bcdc999..08dcddea 100644 --- a/book/src/guides/coding-conventions.md +++ b/book/src/guides/coding-conventions.md @@ -51,7 +51,8 @@ public struct AdminCap has key { id: UID } ### Struct Method 1. Struct methods should be in `snake_case`. -2. If there's multiple structs with the same method, the method should be prefixed with the struct name. In this case, an alias can be added to the method using `use fun`. +2. If there's multiple structs with the same method, the method should be prefixed with the struct + name. In this case, an alias can be added to the method using `use fun`. ```move public fun value(h: &Hero): u64 { h.value } diff --git a/book/src/guides/open-sourcing-libraries.md b/book/src/guides/open-sourcing-libraries.md index 26a763a2..5cb5cef7 100644 --- a/book/src/guides/open-sourcing-libraries.md +++ b/book/src/guides/open-sourcing-libraries.md @@ -1,6 +1,7 @@ # Open Sourcing Libraries -Open sourcing libraries is a great way to contribute to the Move ecosystem. This guide will help you understand how to open source a library, how to write tests, and how to document your library. +Open sourcing libraries is a great way to contribute to the Move ecosystem. This guide will help you +understand how to open source a library, how to write tests, and how to document your library. ## README @@ -16,7 +17,11 @@ TODO: docgen ## Adding Examples -When publishing a package that is intended to be used (an NFT protocol or a library), it is important to showcase how this package can be used. This is where examples come in handy. There's no special functionality for examples in Move, however, there are some conventions that are used to mark examples. First of all, only sources are included into the package bytecode, so any code placed in a different directory will not be included, but will be tested! +When publishing a package that is intended to be used (an NFT protocol or a library), it is +important to showcase how this package can be used. This is where examples come in handy. There's no +special functionality for examples in Move, however, there are some conventions that are used to +mark examples. First of all, only sources are included into the package bytecode, so any code placed +in a different directory will not be included, but will be tested! This is why placing examples into a separate `examples/` directory is a good idea. diff --git a/book/src/guides/upgradeability-practices.md b/book/src/guides/upgradeability-practices.md index 22b1977f..50a9c88e 100644 --- a/book/src/guides/upgradeability-practices.md +++ b/book/src/guides/upgradeability-practices.md @@ -1,6 +1,11 @@ # Upgradeability Practices -To talk about best practices for upgradeability, we need to first understand what can be upgraded in a package. The base premise of upgradeability is that an upgrade should not break public compatibility with the previous version. The parts of the module which can be used in dependent packages should not change their static signature. This applies to modules - a module can not be removed from a package, public structs - they can be used in function signatures and public functions - they can be called from other packages. +To talk about best practices for upgradeability, we need to first understand what can be upgraded in +a package. The base premise of upgradeability is that an upgrade should not break public +compatibility with the previous version. The parts of the module which can be used in dependent +packages should not change their static signature. This applies to modules - a module can not be +removed from a package, public structs - they can be used in function signatures and public +functions - they can be called from other packages. ```move // module can not be removed from the package @@ -58,7 +63,11 @@ TODO: Add a section about entry and friend functions -To discard previous versions of the package, the objects can be versioned. As long as the object contains a version field, and the code which uses the object expects and asserts a specific version, the code can be force-migrated to the new version. Normally, after an upgrade, admin functions can be used to update the version of the shared state, so that the new version of code can be used, and the old version aborts with a version mismatch. +To discard previous versions of the package, the objects can be versioned. As long as the object +contains a version field, and the code which uses the object expects and asserts a specific version, +the code can be force-migrated to the new version. Normally, after an upgrade, admin functions can +be used to update the version of the shared state, so that the new version of code can be used, and +the old version aborts with a version mismatch. ```move module book::versioned_state { @@ -85,7 +94,10 @@ module book::versioned_state { -There's a common pattern in Sui which allows changing the stored configuration of an object while retaining the same object signature. This is done by keeping the base object simple and versioned and adding an actual configuration object as a dynamic field. Using this _anchor_ pattern, the configuration can be changed with package upgrades while keeping the same base object signature. +There's a common pattern in Sui which allows changing the stored configuration of an object while +retaining the same object signature. This is done by keeping the base object simple and versioned +and adding an actual configuration object as a dynamic field. Using this _anchor_ pattern, the +configuration can be changed with package upgrades while keeping the same base object signature. ```move module book::versioned_config { diff --git a/book/src/move-basics/README.md b/book/src/move-basics/README.md index 88daa93b..2602923c 100644 --- a/book/src/move-basics/README.md +++ b/book/src/move-basics/README.md @@ -1,5 +1,10 @@ # Move Basics -This chapter is all about the basic syntax of the Move language. It covers the basics of the language, such as types, modules, functions, and control flow. It focuses on the language without a storage model or a blockchain, and explains the essential concepts of the language. To learn features specific to Sui, such as storage functions and abilities, refer to the [Using Objects](../storage/README.md) chapter, however, it is recommended to start with this chapter first. +This chapter is all about the basic syntax of the Move language. It covers the basics of the +language, such as types, modules, functions, and control flow. It focuses on the language without a +storage model or a blockchain, and explains the essential concepts of the language. To learn +features specific to Sui, such as storage functions and abilities, refer to the +[Using Objects](../storage/README.md) chapter, however, it is recommended to start with this chapter +first. diff --git a/book/src/move-basics/abilities-introduction.md b/book/src/move-basics/abilities-introduction.md index dd2a6702..a18aa82c 100644 --- a/book/src/move-basics/abilities-introduction.md +++ b/book/src/move-basics/abilities-introduction.md @@ -1,16 +1,24 @@ # Abilities: Introduction -Move has a unique type system which allows customizing _type abilities_. [In the previous section](./struct.md), 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_. +Move has a unique type system which allows customizing _type abilities_. +[In the previous section](./struct.md), 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_. -> Throughout the book you will see chapters with name `Ability: `, where `` is the name of the ability. These chapters will cover the ability in detail, how it works, and how to use it in Move. +> Throughout the book you will see chapters with name `Ability: `, where `` is the name +> of the ability. These chapters will cover the ability 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 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. +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. @@ -25,18 +33,28 @@ struct VeryAble has copy, drop { A quick overview of the abilities: -> All of the built-in types, except references, have `copy`, `drop` and `store` abilities. References have `copy` and `drop`. +> 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-ability.md) chapter. -- `drop` - allows the struct to be *dropped* or *discarded*. Explained in the [Ability: Drop](./drop-ability.md) chapter. -- `key` - allows the struct to be used as a *key* in a storage. Explained in the [Ability: Key](./../storage/key-ability.md) chapter. -- `store` - allows the struct to be *stored* in structs with the *key* ability. Explained in the [Ability: Store](./../storage/store-ability.md) chapter. +- `copy` - allows the struct to be _copied_. Explained in the [Ability: Copy](./copy-ability.md) + chapter. +- `drop` - allows the struct to be _dropped_ or _discarded_. Explained in the + [Ability: Drop](./drop-ability.md) chapter. +- `key` - allows the struct to be used as a _key_ in a storage. Explained in the + [Ability: Key](./../storage/key-ability.md) chapter. +- `store` - allows the struct to be _stored_ in structs with the _key_ ability. Explained in the + [Ability: Store](./../storage/store-ability.md) 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. +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](./../programmability/hot-potato.md) chapter. +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](./../programmability/hot-potato.md) chapter. ## Further reading diff --git a/book/src/move-basics/address.md b/book/src/move-basics/address.md index 3a8ec70a..fc8b456d 100644 --- a/book/src/move-basics/address.md +++ b/book/src/move-basics/address.md @@ -18,17 +18,24 @@ Links: --> -To represent [addresses](./../concepts/address.md), Move uses a special type called `address`. It is a 32 byte value that can be used to represent any address on the blockchain. Addresses are used in two syntax forms: hexadecimal addresses prefixed with `0x` and named addresses. +To represent [addresses](./../concepts/address.md), Move uses a special type called `address`. It is +a 32 byte value that can be used to represent any address on the blockchain. Addresses are used in +two syntax forms: hexadecimal addresses prefixed with `0x` and named addresses. ```move {{#include ../../../packages/samples/sources/move-basics/address.move:address_literal}} ``` -An address literal starts with the `@` symbol followed by a hexadecimal number or an identifier. The hexadecimal number is interpreted as a 32 byte value. The identifier is looked up in the [Move.toml](./../concepts/manifest.md) file and replaced with the corresponding address by the compiler. If the identifier is not found in the Move.toml file, the compiler will throw an error. +An address literal starts with the `@` symbol followed by a hexadecimal number or an identifier. The +hexadecimal number is interpreted as a 32 byte value. The identifier is looked up in the +[Move.toml](./../concepts/manifest.md) file and replaced with the corresponding address by the +compiler. If the identifier is not found in the Move.toml file, the compiler will throw an error. ## Conversion -Sui Framework offers a set of helper functions to work with addresses. Given that the address type is a 32 byte value, it can be converted to a `u256` type and vice versa. It can also be converted to and from a `vector` type. +Sui Framework offers a set of helper functions to work with addresses. Given that the address type +is a 32 byte value, it can be converted to a `u256` type and vice versa. It can also be converted to +and from a `vector` type. Example: Convert an address to a `u256` type and back. diff --git a/book/src/move-basics/assert-and-abort.md b/book/src/move-basics/assert-and-abort.md index b5328399..cc6486a7 100644 --- a/book/src/move-basics/assert-and-abort.md +++ b/book/src/move-basics/assert-and-abort.md @@ -20,13 +20,19 @@ Links: - constants (previous section) --> -A transaction can either succeed or fail. Successful execution applies all the changes made to objects and on-chain data, and the transaction is committed to the blockchain. If a transaction aborts, and changes are not applied. The `abort` keyword is used to abort a transaction and revert the changes made so far. +A transaction can either succeed or fail. Successful execution applies all the changes made to +objects and on-chain data, and the transaction is committed to the blockchain. If a transaction +aborts, and changes are not applied. The `abort` keyword is used to abort a transaction and revert +the changes made so far. -> It is important to note that there is no catch mechanism in Move. If a transaction aborts, the changes made so far are reverted, and the transaction is considered failed. +> It is important to note that there is no catch mechanism in Move. If a transaction aborts, the +> changes made so far are reverted, and the transaction is considered failed. ## Abort -The `abort` keyword is used to abort the execution of a transaction. It is used in combination with an abort code, which will be returned to the caller of the transaction. The abort code is an integer of type `u64` and can be any value. +The `abort` keyword is used to abort the execution of a transaction. It is used in combination with +an abort code, which will be returned to the caller of the transaction. The abort code is an integer +of type `u64` and can be any value. ```move {{#include ../../../packages/samples/sources/move-basics/assert-and-abort.move:abort}} @@ -36,7 +42,10 @@ The code above will, of course, abort with abort code `1`. ## assert! -The `assert!` macro is a built-in macro that can be used to assert a condition. If the condition is false, the transaction will abort with the given abort code. The `assert!` macro is a convenient way to abort a transaction if a condition is not met. The macro shortens the code otherwise written with an `if` expression + `abort`. +The `assert!` macro is a built-in macro that can be used to assert a condition. If the condition is +false, the transaction will abort with the given abort code. The `assert!` macro is a convenient way +to abort a transaction if a condition is not met. The macro shortens the code otherwise written with +an `if` expression + `abort`. ```move {{#include ../../../packages/samples/sources/move-basics/assert-and-abort.move:assert}} @@ -44,7 +53,10 @@ The `assert!` macro is a built-in macro that can be used to assert a condition. ## Error constants -To make error codes more descriptive, it is a good practice to define error constants. Error constants are defined as `const` declarations and are usually prefixed with `E` followed by a camel case name. Error constants are no different from other constants and don't have special handling. So their addition is purely a practice for better code readability. +To make error codes more descriptive, it is a good practice to define error constants. Error +constants are defined as `const` declarations and are usually prefixed with `E` followed by a camel +case name. Error constants are no different from other constants and don't have special handling. So +their addition is purely a practice for better code readability. ```move {{#include ../../../packages/samples/sources/move-basics/assert-and-abort.move:error_const}} @@ -53,4 +65,5 @@ To make error codes more descriptive, it is a good practice to define error cons ## Further reading - [Abort and Assert](/reference/abort-and-assert.html) in the Move Language Reference. -- We suggest reading the [Better Error Handling](./../guides/better-error-handling.md) guide to learn about best practices for error handling in Move. +- We suggest reading the [Better Error Handling](./../guides/better-error-handling.md) guide to + learn about best practices for error handling in Move. diff --git a/book/src/move-basics/comments.md b/book/src/move-basics/comments.md index 8659fc82..5f7cabe5 100644 --- a/book/src/move-basics/comments.md +++ b/book/src/move-basics/comments.md @@ -12,7 +12,11 @@ Notes: - give an example of how doc comments are translated --> -Comments are a way to add notes or document your code. They are ignored by the compiler and don't result in the Move bytecode. You can use comments to explain what your code does, to add notes to yourself or other developers, to temporarily remove a part of your code, or to generate documentation. There are three types of comments in Move: line comment, block comment, and doc comment. +Comments are a way to add notes or document your code. They are ignored by the compiler and don't +result in the Move bytecode. You can use comments to explain what your code does, to add notes to +yourself or other developers, to temporarily remove a part of your code, or to generate +documentation. There are three types of comments in Move: line comment, block comment, and doc +comment. ## Line comment @@ -20,7 +24,8 @@ Comments are a way to add notes or document your code. They are ignored by the c {{#include ../../../packages/samples/sources/move-basics/comments.move:line}} ``` -You can use double slash `//` to comment out the rest of the line. Everything after `//` will be ignored by the compiler. +You can use double slash `//` to comment out the rest of the line. Everything after `//` will be +ignored by the compiler. ```Move {{#include ../../../packages/samples/sources/move-basics/comments.move:line_2}} @@ -28,17 +33,22 @@ You can use double slash `//` to comment out the rest of the line. Everything af ## Block comment -Block comments are used to comment out a block of code. They start with `/*` and end with `*/`. Everything between `/*` and `*/` will be ignored by the compiler. You can use block comments to comment out a single line or multiple lines. You can even use them to comment out a part of a line. +Block comments are used to comment out a block of code. They start with `/*` and end with `*/`. +Everything between `/*` and `*/` will be ignored by the compiler. You can use block comments to +comment out a single line or multiple lines. You can even use them to comment out a part of a line. ```Move {{#include ../../../packages/samples/sources/move-basics/comments.move:block}} ``` -This example is a bit extreme, but it shows how you can use block comments to comment out a part of a line. +This example is a bit extreme, but it shows how you can use block comments to comment out a part of +a line. ## Doc comment -Documentation comments are special comments that are used to generate documentation for your code. They are similar to block comments, but they start with three slashes `///` and are placed before the definition of the item they document. +Documentation comments are special comments that are used to generate documentation for your code. +They are similar to block comments, but they start with three slashes `///` and are placed before +the definition of the item they document. ```Move {{#include ../../../packages/samples/sources/move-basics/comments.move:doc}} diff --git a/book/src/move-basics/constants.md b/book/src/move-basics/constants.md index 49f9231a..d3fdeaab 100644 --- a/book/src/move-basics/constants.md +++ b/book/src/move-basics/constants.md @@ -18,7 +18,10 @@ Links: --> -Constants are immutable values that are defined at the module level. They often serve as a way to give names to static values that are used throughout a module. For example, if there's a default price for a product, you might define a constant for it. Constants are stored in the module's bytecode, and each time they are used, the value is copied. +Constants are immutable values that are defined at the module level. They often serve as a way to +give names to static values that are used throughout a module. For example, if there's a default +price for a product, you might define a constant for it. Constants are stored in the module's +bytecode, and each time they are used, the value is copied. ```move {{#include ../../../packages/samples/sources/move-basics/constants.move:shop_price}} @@ -26,7 +29,10 @@ Constants are immutable values that are defined at the module level. They often ## Naming Convention -Constants must start with a capital letter - this is enforced at the compiler level. For constants used as a value, there's a convention to use uppercase letters and underscores to separate words. It's a way to make constants stand out from other identifiers in the code. One exception is made for [error constants](./assert-and-abort.md#assert-and-abort), which are written in ECamelCase. +Constants must start with a capital letter - this is enforced at the compiler level. For constants +used as a value, there's a convention to use uppercase letters and underscores to separate words. +It's a way to make constants stand out from other identifiers in the code. One exception is made for +[error constants](./assert-and-abort.md#assert-and-abort), which are written in ECamelCase. ```move {{#include ../../../packages/samples/sources/move-basics/constants.move:naming}} @@ -34,7 +40,8 @@ Constants must start with a capital letter - this is enforced at the compiler le ## Constants are Immutable -Constants can't be changed and assigned new values. They are part of the package bytecode, and inherently immutable. +Constants can't be changed and assigned new values. They are part of the package bytecode, and +inherently immutable. ```move module book::immutable_constants { @@ -49,13 +56,17 @@ module book::immutable_constants { ## Using Config Pattern -A common use case for an application is to define a set of constants that are used throughout the codebase. But due to constants being private to the module, they can't be accessed from other modules. One way to solve this is to define a "config" module that exports the constants. +A common use case for an application is to define a set of constants that are used throughout the +codebase. But due to constants being private to the module, they can't be accessed from other +modules. One way to solve this is to define a "config" module that exports the constants. ```move {{#include ../../../packages/samples/sources/move-basics/constants.move:config}} ``` -This way other modules can import and read the constants, and the update process is simplified. If the constants need to be changed, only the config module needs to be updated during the package upgrade. +This way other modules can import and read the constants, and the update process is simplified. If +the constants need to be changed, only the config module needs to be updated during the package +upgrade. ## Links diff --git a/book/src/move-basics/control-flow.md b/book/src/move-basics/control-flow.md index e4dd02ae..627a6b43 100644 --- a/book/src/move-basics/control-flow.md +++ b/book/src/move-basics/control-flow.md @@ -19,16 +19,21 @@ Links: --> -Control flow statements are used to control the flow of execution in a program. They are used to make decisions, to repeat a block of code, and to exit a block of code early. Move has the following control flow statements (explained in detail below): +Control flow statements are used to control the flow of execution in a program. They are used to +make decisions, to repeat a block of code, and to exit a block of code early. Move has the following +control flow statements (explained in detail below): -- [`if` and `if-else`](#conditional-statements) - making decisions on whether to execute a block of code +- [`if` and `if-else`](#conditional-statements) - making decisions on whether to execute a block of + code - [`loop` and `while` loops](#repeating-statements-with-loops) - repeating a block of code - [`break` and `continue` statements](#exiting-a-loop-early) - exiting a loop early - [`return`](#return) statement - exiting a function early ## Conditional Statements -The `if` expression is used to make decisions in a program. It evaluates a [boolean expression](./expression.md#literals) and executes a block of code if the expression is true. Paired with `else`, it can execute a different block of code if the expression is false. +The `if` expression is used to make decisions in a program. It evaluates a +[boolean expression](./expression.md#literals) and executes a block of code if the expression is +true. Paired with `else`, it can execute a different block of code if the expression is false. The syntax for the `if` expression is: @@ -37,7 +42,9 @@ if () ; if () else ; ``` -Just like any other expression, `if` requires a semicolon, if there are other expressions following it. The `else` keyword is optional, except for the case when the resulting value is assigned to a variable. We will cover this below. +Just like any other expression, `if` requires a semicolon, if there are other expressions following +it. The `else` keyword is optional, except for the case when the resulting value is assigned to a +variable. We will cover this below. ```move {{#include ../../../packages/samples/sources/move-basics/control-flow.move:if_condition}} @@ -49,21 +56,34 @@ Let's see how we can use `if` and `else` to assign a value to a variable: {{#include ../../../packages/samples/sources/move-basics/control-flow.move:if_else}} ``` -Here we assign the value of the `if` expression to the variable `y`. If `x` is greater than 0, `y` will be assigned the value 1, otherwise 0. The `else` block is necessary, because both branches must return a value of the same type. If we omit the `else` block, the compiler will throw an error. +Here we assign the value of the `if` expression to the variable `y`. If `x` is greater than 0, `y` +will be assigned the value 1, otherwise 0. The `else` block is necessary, because both branches must +return a value of the same type. If we omit the `else` block, the compiler will throw an error. -Conditional expressions are one of the most important control flow statements in Move. They can use either user provided input or some already stored data to make decisions. In particular, they are used in the [`assert!` macro](./assert-and-abort.md) to check if a condition is true, and if not, to abort execution. We will get to it very soon! +Conditional expressions are one of the most important control flow statements in Move. They can use +either user provided input or some already stored data to make decisions. In particular, they are +used in the [`assert!` macro](./assert-and-abort.md) to check if a condition is true, and if not, to +abort execution. We will get to it very soon! ## Repeating Statements with Loops -Loops are used to execute a block of code multiple times. Move has two built-in types of loops: `loop` and `while`. In many cases they can be used interchangeably, but usually `while` is used when the number of iterations is known in advance, and `loop` is used when the number of iterations is not known in advance or there are multiple exit points. +Loops are used to execute a block of code multiple times. Move has two built-in types of loops: +`loop` and `while`. In many cases they can be used interchangeably, but usually `while` is used when +the number of iterations is known in advance, and `loop` is used when the number of iterations is +not known in advance or there are multiple exit points. -Loops are helpful when dealing with collections, such as vectors, or when we want to repeat a block of code until a certain condition is met. However, it is important to be careful with loops, as they can lead to infinite loops, which can lead to gas exhaustion and the transaction being aborted. +Loops are helpful when dealing with collections, such as vectors, or when we want to repeat a block +of code until a certain condition is met. However, it is important to be careful with loops, as they +can lead to infinite loops, which can lead to gas exhaustion and the transaction being aborted. ## The `while` loop -The `while` statement is used to execute a block of code as long as a boolean expression is true. Just like we've seen with `if`, the boolean expression is evaluated before each iteration of the loop. Just like conditional statements, the `while` loop is an expression and requires a semicolon if there are other expressions following it. +The `while` statement is used to execute a block of code as long as a boolean expression is true. +Just like we've seen with `if`, the boolean expression is evaluated before each iteration of the +loop. Just like conditional statements, the `while` loop is an expression and requires a semicolon +if there are other expressions following it. The syntax for the `while` loop is: @@ -79,7 +99,9 @@ Here is an example of a `while` loop with a very simple condition: ## Infinite `loop` -Now let's imagine a scenario where the boolean expression is always `true`. For example, if we literally passed `true` to the `while` condition. As you might expect, this would create an infinite loop, and this is almost what the `loop` statement works like. +Now let's imagine a scenario where the boolean expression is always `true`. For example, if we +literally passed `true` to the `while` condition. As you might expect, this would create an infinite +loop, and this is almost what the `loop` statement works like. ```move {{#include ../../../packages/samples/sources/move-basics/control-flow.move:infinite_while}} @@ -99,11 +121,15 @@ Let's rewrite the previous example using `loop` instead of `while`: -Infinite loops on their own are not very useful in Move, since every operation in Move costs gas, and an infinite loop will lead to gas exhaustion. However, they can be used in combination with `break` and `continue` statements to create more complex loops. +Infinite loops on their own are not very useful in Move, since every operation in Move costs gas, +and an infinite loop will lead to gas exhaustion. However, they can be used in combination with +`break` and `continue` statements to create more complex loops. ## Exiting a Loop Early -As we already mentioned, infinite loops are rather useless on their own. And that's where we introduce the `break` and `continue` statements. They are used to exit a loop early, and to skip the rest of the current iteration, respectively. +As we already mentioned, infinite loops are rather useless on their own. And that's where we +introduce the `break` and `continue` statements. They are used to exit a loop early, and to skip the +rest of the current iteration, respectively. Syntax for the `break` statement is (without a semicolon): @@ -111,17 +137,23 @@ Syntax for the `break` statement is (without a semicolon): break ``` -The `break` statement is used to stop the execution of a loop and exit it early. It is often used in combination with a conditional statement to exit the loop when a certain condition is met. To illustrate this point, let's turn the infinite `loop` from the previous example into something that looks and behaves more like a `while` loop: +The `break` statement is used to stop the execution of a loop and exit it early. It is often used in +combination with a conditional statement to exit the loop when a certain condition is met. To +illustrate this point, let's turn the infinite `loop` from the previous example into something that +looks and behaves more like a `while` loop: ```move {{#include ../../../packages/samples/sources/move-basics/control-flow.move:break_loop}} ``` -Almost identical to the `while` loop, right? The `break` statement is used to exit the loop when `x` is 5. If we remove the `break` statement, the loop will run forever, just like the previous example. +Almost identical to the `while` loop, right? The `break` statement is used to exit the loop when `x` +is 5. If we remove the `break` statement, the loop will run forever, just like the previous example. ## Skipping an Iteration -The `continue` statement is used to skip the rest of the current iteration and start the next one. Similarly to `break`, it is used in combination with a conditional statement to skip the rest of the iteration when a certain condition is met. +The `continue` statement is used to skip the rest of the current iteration and start the next one. +Similarly to `break`, it is used in combination with a conditional statement to skip the rest of the +iteration when a certain condition is met. Syntax for the `continue` statement is (without a semicolon): @@ -139,7 +171,9 @@ The example below skips odd numbers and prints only even numbers from 0 to 10: ## Early Return -The `return` statement is used to exit a [function](./function.md) early and return a value. It is often used in combination with a conditional statement to exit the function when a certain condition is met. The syntax for the `return` statement is: +The `return` statement is used to exit a [function](./function.md) early and return a value. It is +often used in combination with a conditional statement to exit the function when a certain condition +is met. The syntax for the `return` statement is: ```move return @@ -151,4 +185,6 @@ Here is an example of a function that returns a value when a certain condition i {{#include ../../../packages/samples/sources/move-basics/control-flow.move:return_statement}} ``` -Unlike in other languages, the `return` statement is not required for the last expression in a function. The last expression in a function block is automatically returned. However, the `return` statement is useful when we want to exit a function early if a certain condition is met. +Unlike in other languages, the `return` statement is not required for the last expression in a +function. The last expression in a function block is automatically returned. However, the `return` +statement is useful when we want to exit a function early if a certain condition is met. diff --git a/book/src/move-basics/copy-ability.md b/book/src/move-basics/copy-ability.md index c844aa44..e4ba0913 100644 --- a/book/src/move-basics/copy-ability.md +++ b/book/src/move-basics/copy-ability.md @@ -1,6 +1,9 @@ # 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. +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. @@ -8,23 +11,31 @@ However, Move type system allows you to define custom types with the _copy_ abil {{#include ../../../packages/samples/sources/move-basics/copy-ability.move:copyable}} ``` -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. +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 {{#include ../../../packages/samples/sources/move-basics/copy-ability.move:copyable_test}} ``` -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. +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-ability.md). 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. +The `copy` ability is closely related to [`drop` ability](./drop-ability.md). 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 {{#include ../../../packages/samples/sources/move-basics/copy-ability.move:copy_drop}} ``` -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. +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 diff --git a/book/src/move-basics/drop-ability.md b/book/src/move-basics/drop-ability.md index a91ef1d4..d63f296a 100644 --- a/book/src/move-basics/drop-ability.md +++ b/book/src/move-basics/drop-ability.md @@ -40,15 +40,26 @@ Links: ## Drop ability -The `drop` ability - the simplest of them - 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. +The `drop` ability - the simplest of them - 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 {{#include ../../../packages/samples/sources/move-basics/drop-ability.move:main}} ``` -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. +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](./../programmability/witness-and-abstract-implementation.md) section. +A struct with a single `drop` ability is called a _Witness_. We explain the concept of a _Witness_ +in the +[Witness and Abstract Implementation](./../programmability/witness-and-abstract-implementation.md) +section. ## Types with the `drop` Ability diff --git a/book/src/move-basics/expression.md b/book/src/move-basics/expression.md index ab5a0f37..2e3b2da8 100644 --- a/book/src/move-basics/expression.md +++ b/book/src/move-basics/expression.md @@ -1,12 +1,18 @@ # Expression -In programming languages expression is a unit of code which returns a value, in Move, almost everything is an expression, - with the sole exception of `let` statement which is a declaration. In this section, we cover the types of expressions and introduce the concept of scope. +In programming languages expression is a unit of code which returns a value, in Move, almost +everything is an expression, - with the sole exception of `let` statement which is a declaration. In +this section, we cover the types of expressions and introduce the concept of scope. -> Expressions are sequenced with semicolons `;`. If there's "no expression" after the semicolon, the compiler will insert a unit `()` - an empty expression. +> Expressions are sequenced with semicolons `;`. If there's "no expression" after the semicolon, the +> compiler will insert a unit `()` - an empty expression. ## Literals -In the [Primitive Types](./primitive-types.md) section, we introduced the basic types of Move. And to illustrate them, we used literals. A literal is a notation for representing a fixed value in the source code. Literals are used to initialize variables and to pass arguments to functions. Move has the following literals: +In the [Primitive Types](./primitive-types.md) section, we introduced the basic types of Move. And +to illustrate them, we used literals. A literal is a notation for representing a fixed value in the +source code. Literals are used to initialize variables and to pass arguments to functions. Move has +the following literals: - `true` and `false` for boolean values - `0`, `1`, `123123` or other numeric for integer values @@ -20,7 +26,8 @@ In the [Primitive Types](./primitive-types.md) section, we introduced the basic ## Operators -Ariphmetic, logical, and bitwise operators are used to perform operations on values. The result of an operation is a value, so operators are also expressions. +Ariphmetic, logical, and bitwise operators are used to perform operations on values. The result of +an operation is a value, so operators are also expressions. ```move {{#include ../../../packages/samples/sources/move-basics/expression.move:operators}} @@ -28,7 +35,9 @@ Ariphmetic, logical, and bitwise operators are used to perform operations on val ## Blocks -A block is a sequence of statements and expressions, and it returns the value of the last expression in the block. A block is written as a pair of curly braces `{}`. A block is an expression, so it can be used anywhere an expression is expected. +A block is a sequence of statements and expressions, and it returns the value of the last expression +in the block. A block is written as a pair of curly braces `{}`. A block is an expression, so it can +be used anywhere an expression is expected. ```move {{#include ../../../packages/samples/sources/move-basics/expression.move:block}} @@ -36,7 +45,10 @@ A block is a sequence of statements and expressions, and it returns the value of ## Function Calls -We go into detail about functions in the [Functions](./functions.md) section. However, we already used function calls in the previous sections, so it's worth mentioning them here. A function call is an expression that calls a function and returns the value of the last expression in the function body. +We go into detail about functions in the [Functions](./functions.md) section. However, we already +used function calls in the previous sections, so it's worth mentioning them here. A function call is +an expression that calls a function and returns the value of the last expression in the function +body. ```move {{#include ../../../packages/samples/sources/move-basics/expression.move:fun_call}} @@ -44,7 +56,9 @@ We go into detail about functions in the [Functions](./functions.md) section. Ho ## Control Flow Expressions -Control flow expressions are used to control the flow of the program. They are also expressions, so they return a value. We cover control flow expressions in the [Control Flow](./control-flow.md) section. Here's a very brief overview: +Control flow expressions are used to control the flow of the program. They are also expressions, so +they return a value. We cover control flow expressions in the [Control Flow](./control-flow.md) +section. Here's a very brief overview: ```move {{#include ../../../packages/samples/sources/move-basics/expression.move:control_flow}} diff --git a/book/src/move-basics/function.md b/book/src/move-basics/function.md index acb118be..141ece8d 100644 --- a/book/src/move-basics/function.md +++ b/book/src/move-basics/function.md @@ -1,18 +1,30 @@ # Function -Functions are the building blocks of Move programs. They are called from [user transactions](../concepts/user-interaction.md) and from other functions and group executable code into reusable units. Functions can take arguments and return a value. They are declared with the `fun` keyword at the module level. Just like any other module member, by default they're private and can only be accessed from within the module. +Functions are the building blocks of Move programs. They are called from +[user transactions](../concepts/user-interaction.md) and from other functions and group executable +code into reusable units. Functions can take arguments and return a value. They are declared with +the `fun` keyword at the module level. Just like any other module member, by default they're private +and can only be accessed from within the module. ```move {{#include ../../../packages/samples/sources/move-basics/function.move:math}} ``` -In this example, we define a function `add` that takes two arguments of type `u64` and returns their sum. The function is called from the `test_add` function, which is a test function located in the same module. In the test we compare the result of the `add` function with the expected value and abort the execution if the result is different. +In this example, we define a function `add` that takes two arguments of type `u64` and returns their +sum. The function is called from the `test_add` function, which is a test function located in the +same module. In the test we compare the result of the `add` function with the expected value and +abort the execution if the result is different. ## Function declaration -> There's a convention to call functions in Move with the `snake_case` naming convention. This means that the function name should be all lowercase with words separated by underscores. For example, `do_something`, `add`, `get_balance`, `is_authorized`, and so on. +> There's a convention to call functions in Move with the `snake_case` naming convention. This means +> that the function name should be all lowercase with words separated by underscores. For example, +> `do_something`, `add`, `get_balance`, `is_authorized`, and so on. -A function is declared with the `fun` keyword followed by the function name (a valid Move identifier), a list of arguments in parentheses, and a return type. The function body is a block of code that contains a sequence of statements and expressions. The last expression in the function body is the return value of the function. +A function is declared with the `fun` keyword followed by the function name (a valid Move +identifier), a list of arguments in parentheses, and a return type. The function body is a block of +code that contains a sequence of statements and expressions. The last expression in the function +body is the return value of the function. ```move {{#include ../../../packages/samples/sources/move-basics/function.move:return_nothing}} @@ -20,7 +32,10 @@ A function is declared with the `fun` keyword followed by the function name (a v ## Accessing functions -Just like any other module member, functions can be imported and accessed via a path. The path consists of the module path and the function name separated by `::`. For example, if you have a function called `add` in the `math` module in the `book` package, the path to it will be `book::math::add`, or, if the module is imported, `math::add`. +Just like any other module member, functions can be imported and accessed via a path. The path +consists of the module path and the function name separated by `::`. For example, if you have a +function called `add` in the `math` module in the `book` package, the path to it will be +`book::math::add`, or, if the module is imported, `math::add`. ```move {{#include ../../../packages/samples/sources/move-basics/function.move:use_math}} @@ -28,19 +43,23 @@ Just like any other module member, functions can be imported and accessed via a ## Multiple return values -Move functions can return multiple values, which is useful when you need to return more than one value from a function. The return type of the function is a tuple of types. The return value is a tuple of expressions. +Move functions can return multiple values, which is useful when you need to return more than one +value from a function. The return type of the function is a tuple of types. The return value is a +tuple of expressions. ```move {{#include ../../../packages/samples/sources/move-basics/function.move:tuple_return}} ``` -Result of a function call with tuple return has to be unpacked into variables via `let (tuple)` syntax: +Result of a function call with tuple return has to be unpacked into variables via `let (tuple)` +syntax: ```move {{#include ../../../packages/samples/sources/move-basics/function.move:tuple_return_imm}} ``` -If any of the declared values need to be declared as mutable, the `mut` keyword is placed before the variable name: +If any of the declared values need to be declared as mutable, the `mut` keyword is placed before the +variable name: ```move {{#include ../../../packages/samples/sources/move-basics/function.move:tuple_return_mut}} diff --git a/book/src/move-basics/generics.md b/book/src/move-basics/generics.md index e5fde63c..3033a019 100644 --- a/book/src/move-basics/generics.md +++ b/book/src/move-basics/generics.md @@ -1,42 +1,58 @@ # Generics -Generics are a way to define a type or function that can work with any type. This is useful when you want to write a function which can be used with different types, or when you want to define a type that can hold any other type. Generics are the foundation of many advanced features in Move, such as collections, abstract implementations, and more. +Generics are a way to define a type or function that can work with any type. This is useful when you +want to write a function which can be used with different types, or when you want to define a type +that can hold any other type. Generics are the foundation of many advanced features in Move, such as +collections, abstract implementations, and more. ## In the Standard Library -In this chapter we already mentioned the [vector](./vector.md) type, which is a generic type that can hold any other type. Another example of a generic type in the standard library is the [Option](./option.md) type, which is used to represent a value that may or may not be present. +In this chapter we already mentioned the [vector](./vector.md) type, which is a generic type that +can hold any other type. Another example of a generic type in the standard library is the +[Option](./option.md) type, which is used to represent a value that may or may not be present. ## Generic Syntax -To define a generic type or function, a type signature needs to have a list of generic parameters enclosed in angle brackets (`<` and `>`). The generic parameters are separated by commas. +To define a generic type or function, a type signature needs to have a list of generic parameters +enclosed in angle brackets (`<` and `>`). The generic parameters are separated by commas. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:container}} ``` -In the example above, `Container` is a generic type with a single type parameter `T`, the `value` field of the container stores the `T`. The `new` function is a generic function with a single type parameter `T`, and it returns a `Container` with the given value. Generic types must be initialed with a concrete type, and generic functions must be called with a concrete type. +In the example above, `Container` is a generic type with a single type parameter `T`, the `value` +field of the container stores the `T`. The `new` function is a generic function with a single type +parameter `T`, and it returns a `Container` with the given value. Generic types must be initialed +with a concrete type, and generic functions must be called with a concrete type. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:test_container}} ``` -In the test function `test_generic` we demonstrate three equivalent ways to create a new `Container` with a `u8` value. Because numeric types need to be inferred, we specify the type of the number literal. +In the test function `test_generic` we demonstrate three equivalent ways to create a new `Container` +with a `u8` value. Because numeric types need to be inferred, we specify the type of the number +literal. ## Multiple Type Parameters -You can define a type or function with multiple type parameters. The type parameters are then separated by commas. +You can define a type or function with multiple type parameters. The type parameters are then +separated by commas. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:pair}} ``` -In the example above, `Pair` is a generic type with two type parameters `T` and `U`, and the `new_pair` function is a generic function with two type parameters `T` and `U`. The function returns a `Pair` with the given values. The order of the type parameters is important, and it should match the order of the type parameters in the type signature. +In the example above, `Pair` is a generic type with two type parameters `T` and `U`, and the +`new_pair` function is a generic function with two type parameters `T` and `U`. The function returns +a `Pair` with the given values. The order of the type parameters is important, and it should match +the order of the type parameters in the type signature. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:test_pair}} ``` -If we added another instance where we swapped type parameters in the `new_pair` function, and tried to compare two types, we'd see that the type signatures are different, and cannot be compared. +If we added another instance where we swapped type parameters in the `new_pair` function, and tried +to compare two types, we'd see that the type signatures are different, and cannot be compared. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:test_pair_swap}} @@ -46,13 +62,19 @@ Types for variables `pair1` and `pair2` are different, and the comparison will n ## Why Generics? -In the examples above we focused on instantiating generic types and calling generic functions to create instances of these types. However, the real power of generics is the ability to define shared behavior for the base, generic type, and then use it independently of the concrete types. This is especially useful when working with collections, abstract implementations, and other advanced features in Move. +In the examples above we focused on instantiating generic types and calling generic functions to +create instances of these types. However, the real power of generics is the ability to define shared +behavior for the base, generic type, and then use it independently of the concrete types. This is +especially useful when working with collections, abstract implementations, and other advanced +features in Move. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:user}} ``` -In the example above, `User` is a generic type with a single type parameter `T`, with shared fields `name` and `age`, and the generic `metadata` field which can store any type. No matter what the `metadata` is, all of the instances of `User` will have the same fields and methods. +In the example above, `User` is a generic type with a single type parameter `T`, with shared fields +`name` and `age`, and the generic `metadata` field which can store any type. No matter what the +`metadata` is, all of the instances of `User` will have the same fields and methods. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:update_user}} @@ -60,29 +82,40 @@ In the example above, `User` is a generic type with a single type parameter `T`, ## Phantom Type Parameters -In some cases, you may want to define a generic type with a type parameter that is not used in the fields or methods of the type. This is called a _phantom type parameter_. Phantom type parameters are useful when you want to define a type that can hold any other type, but you want to enforce some constraints on the type parameter. +In some cases, you may want to define a generic type with a type parameter that is not used in the +fields or methods of the type. This is called a _phantom type parameter_. Phantom type parameters +are useful when you want to define a type that can hold any other type, but you want to enforce some +constraints on the type parameter. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:phantom}} ``` -The `Coin` type here does not contain any fields or methods that use the type parameter `T`. It is used to differentiate between different types of coins, and to enforce some constraints on the type parameter `T`. +The `Coin` type here does not contain any fields or methods that use the type parameter `T`. It is +used to differentiate between different types of coins, and to enforce some constraints on the type +parameter `T`. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:test_phantom}} ``` -In the example above, we demonstrate how to create two different instances of `Coin` with different phantom type parameters `USD` and `EUR`. The type parameter `T` is not used in the fields or methods of the `Coin` type, but it is used to differentiate between different types of coins. It will make sure that the `USD` and `EUR` coins are not mixed up. +In the example above, we demonstrate how to create two different instances of `Coin` with different +phantom type parameters `USD` and `EUR`. The type parameter `T` is not used in the fields or methods +of the `Coin` type, but it is used to differentiate between different types of coins. It will make +sure that the `USD` and `EUR` coins are not mixed up. ## Constraints on Type Parameters -Type parameters can be constrained to have certain abilities. This is useful when you need the inner type to allow certain behavior, such as _copy_ or _drop_. The syntax for constraining a type parameter is `T: + `. +Type parameters can be constrained to have certain abilities. This is useful when you need the inner +type to allow certain behavior, such as _copy_ or _drop_. The syntax for constraining a type +parameter is `T: + `. ```move {{#include ../../../packages/samples/sources/move-basics/generics.move:constraints}} ``` -Move Compiler will enforce that the type parameter `T` has the specified abilities. If the type parameter does not have the specified abilities, the code will not compile. +Move Compiler will enforce that the type parameter `T` has the specified abilities. If the type +parameter does not have the specified abilities, the code will not compile. diff --git a/book/src/move-basics/importing-modules.md b/book/src/move-basics/importing-modules.md index a408ff10..98695431 100644 --- a/book/src/move-basics/importing-modules.md +++ b/book/src/move-basics/importing-modules.md @@ -19,11 +19,15 @@ Goals: --> -Move achieves high modularity and code reuse by allowing module imports. Modules within the same package can import each other, and a new package can depend on already existing packages and use their modules too. This section will cover the basics of importing modules and how to use them in your own code. +Move achieves high modularity and code reuse by allowing module imports. Modules within the same +package can import each other, and a new package can depend on already existing packages and use +their modules too. This section will cover the basics of importing modules and how to use them in +your own code. ## Importing a Module -Modules defined in the same package can import each other. The `use` keyword is followed by the module path, which consists of the package address (or alias) and the module name separated by `::`. +Modules defined in the same package can import each other. The `use` keyword is followed by the +module path, which consists of the package address (or alias) and the module name separated by `::`. ```move // File: sources/module_one.move @@ -39,7 +43,9 @@ Another module defined in the same package can import the first module using the ## Importing Members -You can also import specific members from a module. This is useful when you only need a single function or a single type from a module. The syntax is the same as for importing a module, but you add the member name after the module path. +You can also import specific members from a module. This is useful when you only need a single +function or a single type from a module. The syntax is the same as for importing a module, but you +add the member name after the module path. ```move {{#include ../../../packages/samples/sources/move-basics/importing-modules.move:members}} @@ -47,15 +53,20 @@ You can also import specific members from a module. This is useful when you only ## Grouping Imports -Imports can be grouped into a single `use` statement using the curly braces `{}`. This is useful when you need to import multiple members from the same module. Move allows grouping imports from the same module and from the same package. +Imports can be grouped into a single `use` statement using the curly braces `{}`. This is useful +when you need to import multiple members from the same module. Move allows grouping imports from the +same module and from the same package. ```move {{#include ../../../packages/samples/sources/move-basics/importing-modules.move:grouped}} ``` -Single function imports are less common in Move, since the function names can overlap and cause confusion. A recommended practice is to import the entire module and use the module path to access the function. Types have unique names and should be imported individually. +Single function imports are less common in Move, since the function names can overlap and cause +confusion. A recommended practice is to import the entire module and use the module path to access +the function. Types have unique names and should be imported individually. -To import members and the module itself in the group import, you can use the `Self` keyword. The `Self` keyword refers to the module itself and can be used to import the module and its members. +To import members and the module itself in the group import, you can use the `Self` keyword. The +`Self` keyword refers to the module itself and can be used to import the module and its members. ```move {{#include ../../../packages/samples/sources/move-basics/importing-modules.move:self}} @@ -63,7 +74,11 @@ To import members and the module itself in the group import, you can use the `Se ## Resolving Name Conflicts -When importing multiple members from different modules, it is possible to have name conflicts. For example, if you import two modules that both have a function with the same name, you will need to use the module path to access the function. It is also possible to have modules with the same name in different packages. To resolve the conflict and avoid ambiguity, Move offers the `as` keyword to rename the imported member. +When importing multiple members from different modules, it is possible to have name conflicts. For +example, if you import two modules that both have a function with the same name, you will need to +use the module path to access the function. It is also possible to have modules with the same name +in different packages. To resolve the conflict and avoid ambiguity, Move offers the `as` keyword to +rename the imported member. ```move {{#include ../../../packages/samples/sources/move-basics/importing-modules.move:conflict}} @@ -71,7 +86,10 @@ When importing multiple members from different modules, it is possible to have n ## Adding an External Dependency -Every new package generated via the `sui` binary features a `Move.toml` file with a single dependency on the _Sui Framework_ package. The Sui Framework depends on the _Standard Library_ package. And both of these packages are available in default configuration. Package dependencies are defined in the [Package Manifest](./../concepts/manifest.md) as follows: +Every new package generated via the `sui` binary features a `Move.toml` file with a single +dependency on the _Sui Framework_ package. The Sui Framework depends on the _Standard Library_ +package. And both of these packages are available in default configuration. Package dependencies are +defined in the [Package Manifest](./../concepts/manifest.md) as follows: ```toml [dependencies] @@ -79,15 +97,23 @@ Sui = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-fram Local = { local = "../my_other_package" } ``` -The `dependencies` section contains a list of package dependencies. The key is the name of the package, and the value is either a git import table or a local path. The git import contains the URL of the package, the subdirectory where the package is located, and the revision of the package. The local path is a relative path to the package directory. +The `dependencies` section contains a list of package dependencies. The key is the name of the +package, and the value is either a git import table or a local path. The git import contains the URL +of the package, the subdirectory where the package is located, and the revision of the package. The +local path is a relative path to the package directory. -If a dependency is added to the `Move.toml` file, the compiler will automatically fetch (and later refetch) the dependencies when building the package. +If a dependency is added to the `Move.toml` file, the compiler will automatically fetch (and later +refetch) the dependencies when building the package. ## Importing a Module from Another Package -Normally, packages define their addresses in the `[addresses]` section, so you can use the alias instead of the address. For example, instead of `0x2::coin` module, you would use `sui::coin`. The `sui` alias is defined in the Sui Framework package. Similarly, the `std` alias is defined in the Standard Library package and can be used to access the standard library modules. +Normally, packages define their addresses in the `[addresses]` section, so you can use the alias +instead of the address. For example, instead of `0x2::coin` module, you would use `sui::coin`. The +`sui` alias is defined in the Sui Framework package. Similarly, the `std` alias is defined in the +Standard Library package and can be used to access the standard library modules. -To import a module from another package, you use the `use` keyword followed by the module path. The module path consists of the package address (or alias) and the module name separated by `::`. +To import a module from another package, you use the `use` keyword followed by the module path. The +module path consists of the package address (or alias) and the module name separated by `::`. ```move {{#include ../../../packages/samples/sources/move-basics/importing-modules.move:external}} diff --git a/book/src/move-basics/module.md b/book/src/move-basics/module.md index 32642cee..15a07336 100644 --- a/book/src/move-basics/module.md +++ b/book/src/move-basics/module.md @@ -12,13 +12,20 @@ Notes: --> -Module is the base unit of code organization in Move. Modules are used to group and isolate code, and all of the members of the module are private to the module by default. In this section you will learn how to define a module, how to declare its members and how to access them from other modules. +Module is the base unit of code organization in Move. Modules are used to group and isolate code, +and all of the members of the module are private to the module by default. In this section you will +learn how to define a module, how to declare its members and how to access them from other modules. ## Module declaration -Modules are declared using the `module` keyword followed by the package address, module name and the module body inside the curly braces `{}`. The module name should be in `snake_case` - all lowercase letters with underscores between words. Modules names must be unique in the package. +Modules are declared using the `module` keyword followed by the package address, module name and the +module body inside the curly braces `{}`. The module name should be in `snake_case` - all lowercase +letters with underscores between words. Modules names must be unique in the package. -Usually, a single file in the `sources/` folder contains a single module. The file name should match the module name - for example, a `donut_shop` module should be stored in the `donut_shop.move` file. You can read more about coding conventions in the [Coding Conventions](../special-topics/coding-conventions.md) section. +Usually, a single file in the `sources/` folder contains a single module. The file name should match +the module name - for example, a `donut_shop` module should be stored in the `donut_shop.move` file. +You can read more about coding conventions in the +[Coding Conventions](../special-topics/coding-conventions.md) section. ```Move {{#include ../../../packages/samples/sources/move-basics/module.move:module}} @@ -34,7 +41,10 @@ Structs, functions, constants and imports all part of the module: ## Address / Named address -Module address can be specified as both: an address _literal_ (does not require the `@` prefix) or a named address specified in the [Package Manifest](../concepts/manifest.md). In the example below, both are identical because there's a `book = "0x0"` record in the `[addresses]` section of the `Move.toml`. +Module address can be specified as both: an address _literal_ (does not require the `@` prefix) or a +named address specified in the [Package Manifest](../concepts/manifest.md). In the example below, +both are identical because there's a `book = "0x0"` record in the `[addresses]` section of the +`Move.toml`. ```Move {{#include ../../../packages/samples/sources/move-basics/module.move:address_literal}} @@ -50,7 +60,8 @@ book = "0x0" ## Module members -Module members are declared inside the module body. To illustrate that, let's define a simple module with a struct, a function and a constant: +Module members are declared inside the module body. To illustrate that, let's define a simple module +with a struct, a function and a constant: ```Move {{#include ../../../packages/samples/sources/move-basics/module.move:members}} diff --git a/book/src/move-basics/option.md b/book/src/move-basics/option.md index b59d8796..05bb052d 100644 --- a/book/src/move-basics/option.md +++ b/book/src/move-basics/option.md @@ -1,35 +1,51 @@ # Option -Option is a type that represents an optional value which may or may not exist. The concept of Option in Move is borrowed from Rust, and it is a very useful primitive in Move. `Option` is defined in the [Standard Library](./standard-library.md), and is defined as follows: +Option is a type that represents an optional value which may or may not exist. The concept of Option +in Move is borrowed from Rust, and it is a very useful primitive in Move. `Option` is defined in the +[Standard Library](./standard-library.md), and is defined as follows: File: move-stdlib/source/option.move ```move +// File: move-stdlib/source/option.move /// Abstraction of a value that may or may not be present. struct Option has copy, drop, store { vec: vector } ``` -> The 'std::option' module is implicitly imported in every module, and you don't need to add an import. +> The 'std::option' module is implicitly imported in every module, and you don't need to add an +> import. -The `Option` is a generic type which takes a type parameter `Element`. It has a single field `vec` which is a `vector` of `Element`. Vector can have length 0 or 1, and this is used to represent the presence or absence of a value. +The `Option` is a generic type which takes a type parameter `Element`. It has a single field `vec` +which is a `vector` of `Element`. Vector can have length 0 or 1, and this is used to represent the +presence or absence of a value. -Option type has two variants: `Some` and `None`. `Some` variant contains a value and `None` variant represents the absence of a value. The `Option` type is used to represent the absence of a value in a type-safe way, and it is used to avoid the need for empty or `undefined` values. +Option type has two variants: `Some` and `None`. `Some` variant contains a value and `None` variant +represents the absence of a value. The `Option` type is used to represent the absence of a value in +a type-safe way, and it is used to avoid the need for empty or `undefined` values. ## In Practice -To showcase why Option type is necessary, let's look at an example. Consider an application which takes a user input and stores it in a variable. Some fields are required, and some are optional. For example, a user's middle name is optional. While we could use an empty string to represent the absence of a middle name, it would require extra checks to differentiate between an empty string and a missing middle name. Instead, we can use the `Option` type to represent the middle name. +To showcase why Option type is necessary, let's look at an example. Consider an application which +takes a user input and stores it in a variable. Some fields are required, and some are optional. For +example, a user's middle name is optional. While we could use an empty string to represent the +absence of a middle name, it would require extra checks to differentiate between an empty string and +a missing middle name. Instead, we can use the `Option` type to represent the middle name. ```move {{#include ../../../packages/samples/sources/move-basics/option.move:registry}} ``` -In the example above, the `middle_name` field is of type `Option`. This means that the `middle_name` field can either contain a `String` value or be empty. This makes it clear that the middle name is optional, and it avoids the need for extra checks to differentiate between an empty string and a missing middle name. +In the example above, the `middle_name` field is of type `Option`. This means that the +`middle_name` field can either contain a `String` value or be empty. This makes it clear that the +middle name is optional, and it avoids the need for extra checks to differentiate between an empty +string and a missing middle name. ## Using Option -To use the `Option` type, you need to import the `std::option` module and use the `Option` type. You can then create an `Option` value using the `some` or `none` methods. +To use the `Option` type, you need to import the `std::option` module and use the `Option` type. You +can then create an `Option` value using the `some` or `none` methods. ```move {{#include ../../../packages/samples/sources/move-basics/option.move:usage}} diff --git a/book/src/move-basics/ownership-and-scope.md b/book/src/move-basics/ownership-and-scope.md index 13137c2d..1d1bb039 100644 --- a/book/src/move-basics/ownership-and-scope.md +++ b/book/src/move-basics/ownership-and-scope.md @@ -1,6 +1,9 @@ # Ownership and Scope -Every variable in Move has a scope and an owner. The scope is the range of code where the variable is valid, and the owner is the scope that this variable belongs to. Once the owner scope ends, the variable is dropped. This is a fundamental concept in Move, and it is important to understand how it works. +Every variable in Move has a scope and an owner. The scope is the range of code where the variable +is valid, and the owner is the scope that this variable belongs to. Once the owner scope ends, the +variable is dropped. This is a fundamental concept in Move, and it is important to understand how it +works. -For simple values, Move has a number of built-in primitive types. They're the base that makes up all other types. The primitive types are: +For simple values, Move has a number of built-in primitive types. They're the base that makes up all +other types. The primitive types are: - [Booleans](#booleans) - [Unsigned Integers](#integers) - [Address](./address.md) - covered in the next section -However, before we get to the types, let's first look at how to declare and assign variables in Move. +However, before we get to the types, let's first look at how to declare and assign variables in +Move. ## Variables and assignment -Variables are declared using the `let` keyword. They are immutable by default, but can be made mutable using the `let mut` keyword. The syntax for the `let mut` statement is: +Variables are declared using the `let` keyword. They are immutable by default, but can be made +mutable using the `let mut` keyword. The syntax for the `let mut` statement is: ``` let [: ] = ; @@ -45,14 +48,17 @@ let x: u8 = 43; ## Booleans -The `bool` type represents a boolean value - yes or no, true or false. It has two possible values: `true` and `false` which are keywords in Move. For booleans, there's no need to explicitly specify the type - the compiler can infer it from the value. +The `bool` type represents a boolean value - yes or no, true or false. It has two possible values: +`true` and `false` which are keywords in Move. For booleans, there's no need to explicitly specify +the type - the compiler can infer it from the value. ```move let x = true; let y = false; ``` -Booleans are often used to store flags and to control the flow of the program. Please, refer to the [Control Flow](./control-flow.md) section for more information. +Booleans are often used to store flags and to control the flow of the program. Please, refer to the +[Control Flow](./control-flow.md) section for more information. ## Integer Types @@ -72,7 +78,10 @@ let y: u16 = 42; let z: u256 = 42; ``` -Unlike booleans, integer types need to be inferred. In most of the cases, the compiler will infer the type from the value, usually defaulting to `u64`. However, sometimes the compiler is unable to infer the type and will require an explicit type annotation. It can either be provided during assignment or by using a type suffix. +Unlike booleans, integer types need to be inferred. In most of the cases, the compiler will infer +the type from the value, usually defaulting to `u64`. However, sometimes the compiler is unable to +infer the type and will require an explicit type annotation. It can either be provided during +assignment or by using a type suffix. ```move // Both are equivalent @@ -82,7 +91,8 @@ let x = 42u8; ### Operations -Move supports the standard arithmetic operations for integers: addition, subtraction, multiplication, division, and remainder. The syntax for these operations is: +Move supports the standard arithmetic operations for integers: addition, subtraction, +multiplication, division, and remainder. The syntax for these operations is: | Syntax | Operation | Aborts If | | ------ | ------------------- | ---------------------------------------- | @@ -92,7 +102,9 @@ Move supports the standard arithmetic operations for integers: addition, subtrac | % | modular division | The divisor is 0 | | / | truncating division | The divisor is 0 | -The type of the operands _must match_, otherwise, the compiler will raise an error. The result of the operation will be of the same type as the operands. To perform operations on different types, the operands need to be cast to the same type. +The type of the operands _must match_, otherwise, the compiler will raise an error. The result of +the operation will be of the same type as the operands. To perform operations on different types, +the operands need to be cast to the same type. @@ -122,7 +134,8 @@ let z: u16 = (x as u16) + ((y as u16) * 2); ### Overflow -Move does not support overflow / underflow, an operation that results in a value outside the range of the type will raise a runtime error. This is a safety feature to prevent unexpected behavior. +Move does not support overflow / underflow, an operation that results in a value outside the range +of the type will raise a runtime error. This is a safety feature to prevent unexpected behavior. ```move let x = 255u8; diff --git a/book/src/move-basics/references.md b/book/src/move-basics/references.md index 2a77fec9..72b27c24 100644 --- a/book/src/move-basics/references.md +++ b/book/src/move-basics/references.md @@ -16,9 +16,15 @@ Notes: --> -In the [Ownership and Scope](./ownership-and-scope.md) section, we explained that when a value is passed to a function, it is _moved_ to the function's scope. This means that the function becomes the owner of the value, and the original scope (owner) can no longer use it. This is an important concept in Move, as it ensures that the value is not used in multiple places at the same time. However, there are use cases when we want to pass a value to a function but retain the ownership. This is where references come into play. +In the [Ownership and Scope](./ownership-and-scope.md) section, we explained that when a value is +passed to a function, it is _moved_ to the function's scope. This means that the function becomes +the owner of the value, and the original scope (owner) can no longer use it. This is an important +concept in Move, as it ensures that the value is not used in multiple places at the same time. +However, there are use cases when we want to pass a value to a function but retain the ownership. +This is where references come into play. -To illustrate this, let's consider a simple example - an application for a metro (subway) pass. We will look at 4 different scenarios: +To illustrate this, let's consider a simple example - an application for a metro (subway) pass. We +will look at 4 different scenarios: 1. Card can be purchased at the kiosk for a fixed price 2. Card can be shown to inspectors to prove that the passenger has a valid pass @@ -27,7 +33,9 @@ To illustrate this, let's consider a simple example - an application for a metro ## Layout -The initial layout of the metro pass application is simple. We define the `Card` type and the `USES` [constant](./constants.md) that represents the number of rides for a single card. We also add an [error constant](./assert-and-abort.md#error-constants) for the case when the card is empty. +The initial layout of the metro pass application is simple. We define the `Card` type and the `USES` +[constant](./constants.md) that represents the number of rides for a single card. We also add an +[error constant](./assert-and-abort.md#error-constants) for the case when the card is empty. ```move module book::metro_pass { @@ -41,35 +49,48 @@ module book::metro_pass { ## Reference -References are a way to _show_ a value to a function without giving up the ownership. In our case, when we show the Card to the inspector, we don't want to give up the ownership of it, and we don't allow them to spend the rides. We just want to allow _reading_ the value of the Card and prove its ownership. +References are a way to _show_ a value to a function without giving up the ownership. In our case, +when we show the Card to the inspector, we don't want to give up the ownership of it, and we don't +allow them to spend the rides. We just want to allow _reading_ the value of the Card and prove its +ownership. -To do so, in the function signature, we use the `&` symbol to indicate that we are passing a reference to the value, not the value itself. +To do so, in the function signature, we use the `&` symbol to indicate that we are passing a +reference to the value, not the value itself. ```move {{#include ../../../packages/samples/sources/move-basics/references.move:immutable}} ``` -Now the function can't take the ownership of the card, and it can't spend the rides. But it can read its value. Worth noting, that a signature like this makes it impossible to call the function without a Card at all. This is an important property which allows the [Capability Pattern](./../programmability/capability.md) which we will cover in the next chapters. +Now the function can't take the ownership of the card, and it can't spend the rides. But it can read +its value. Worth noting, that a signature like this makes it impossible to call the function without +a Card at all. This is an important property which allows the +[Capability Pattern](./../programmability/capability.md) which we will cover in the next chapters. ## Mutable Reference -In some cases, we want to allow the function to change the value of the Card. For example, when we use the Card at the turnstile, we want to spend a ride. To implement it, we use the `&mut` keyword in the function signature. +In some cases, we want to allow the function to change the value of the Card. For example, when we +use the Card at the turnstile, we want to spend a ride. To implement it, we use the `&mut` keyword +in the function signature. ```move {{#include ../../../packages/samples/sources/move-basics/references.move:mutable}} ``` -As you can see in the function body, the `&mut` reference allows mutating the value, and the function can spend the rides. +As you can see in the function body, the `&mut` reference allows mutating the value, and the +function can spend the rides. ## Passing by Value -Lastly, let's give an illustration of what happens when we pass the value itself to the function. In this case, the function takes the ownership of the value, and the original scope can no longer use it. The owner of the Card can recycle it, and, hence, lose the ownership. +Lastly, let's give an illustration of what happens when we pass the value itself to the function. In +this case, the function takes the ownership of the value, and the original scope can no longer use +it. The owner of the Card can recycle it, and, hence, lose the ownership. ```move {{#include ../../../packages/samples/sources/move-basics/references.move:move}} ``` -In the `recycle` function, the Card is _taken by value_ and can be unpacked and destroyed. The original scope can't use it anymore. +In the `recycle` function, the Card is _taken by value_ and can be unpacked and destroyed. The +original scope can't use it anymore. ## Full Example diff --git a/book/src/move-basics/standard-library.md b/book/src/move-basics/standard-library.md index 2d84872e..da25e58a 100644 --- a/book/src/move-basics/standard-library.md +++ b/book/src/move-basics/standard-library.md @@ -2,11 +2,16 @@ -The Move Standard Library provides functionality for native types and operations. It is a standard collection of modules which do not interact with the storage, but provide basic tools for working and manipulating the data. It is the only dependency of the [Sui Framework](../programmability/sui-framework.md), and is imported together with it. +The Move Standard Library provides functionality for native types and operations. It is a standard +collection of modules which do not interact with the storage, but provide basic tools for working +and manipulating the data. It is the only dependency of the +[Sui Framework](../programmability/sui-framework.md), and is imported together with it. ## Most Common Modules -In this book we go into detail about most of the modules in the Standard Library, however, it is also helpful to give an overview of the features, so that you can get a sense of what is available and which module implements it. +In this book we go into detail about most of the modules in the Standard Library, however, it is +also helpful to give an overview of the features, so that you can get a sense of what is available +and which module implements it.
@@ -38,7 +43,8 @@ std = "0x1" ## Implicit Imports -Some of the modules are imported implicitly, and are available in the module without explicit `use` import. For Standard Library, these modules and types are: +Some of the modules are imported implicitly, and are available in the module without explicit `use` +import. For Standard Library, these modules and types are: - std::vector - std::option @@ -46,7 +52,9 @@ Some of the modules are imported implicitly, and are available in the module wit ## Importing std without Sui Framework -The Move Standard Library can be imported to the package directly. However, `std` alone is not enough to build a meaningful application, as it does not provide any storage capabilities, and can't interact with the on-chain state. +The Move Standard Library can be imported to the package directly. However, `std` alone is not +enough to build a meaningful application, as it does not provide any storage capabilities, and can't +interact with the on-chain state. ```toml MoveStdlib = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/sui-framework/packages/move-stdlib", rev = "framework/mainnet" } @@ -54,4 +62,5 @@ MoveStdlib = { git = "https://github.com/MystenLabs/sui.git", subdir = "crates/s ## Source Code -The source code of the Move Standard Library is available in the [Sui repository](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/move-stdlib/sources). +The source code of the Move Standard Library is available in the +[Sui repository](https://github.com/MystenLabs/sui/tree/main/crates/sui-framework/packages/move-stdlib/sources). diff --git a/book/src/move-basics/string.md b/book/src/move-basics/string.md index 6435d980..88d25e02 100644 --- a/book/src/move-basics/string.md +++ b/book/src/move-basics/string.md @@ -1,8 +1,12 @@ # String -While Move does not have a built-in to represent strings, it does have a `string` module in the [Standard Library](./standard-library.md) that provides a `String` type. The `string` module represents UTF-8 encoded strings, and another module, `ascii`, provides an ASCII-only `String` type. +While Move does not have a built-in to represent strings, it does have a `string` module in the +[Standard Library](./standard-library.md) that provides a `String` type. The `string` module +represents UTF-8 encoded strings, and another module, `ascii`, provides an ASCII-only `String` type. -> Sui execution environment automatically converts bytevector into `String` in transaction inputs. So in many cases, String does not to be constructed in the [Transaction Block](./../concepts/what-is-a-transaction.md). +> Sui execution environment automatically converts bytevector into `String` in transaction inputs. +> So in many cases, String does not to be constructed in the +> [Transaction Block](./../concepts/what-is-a-transaction.md). -However, Ethereum's programming model lacked a native representation of assets. In other words, externally, a Smart Contract behaved like an asset, but the language itself did not have a way to inherently represent assets. From the start, Move aimed to provide a first-class abstraction for assets, opening up new avenues for thinking about and programming assets. +However, Ethereum's programming model lacked a native representation of assets. In other words, +externally, a Smart Contract behaved like an asset, but the language itself did not have a way to +inherently represent assets. From the start, Move aimed to provide a first-class abstraction for +assets, opening up new avenues for thinking about and programming assets. It is important to highlight which properties are essential for an asset: -- **Ownership:** Every asset is associated with an owner(s), mirroring the straightforward concept of ownership in the physical world—just as you own a car, you can own a digital asset. Move enforces ownership in such a way that once an asset is _moved_, the previous owner completely loses any control over it. This mechanism ensures a clear and secure change of ownership. +- **Ownership:** Every asset is associated with an owner(s), mirroring the straightforward concept + of ownership in the physical world—just as you own a car, you can own a digital asset. Move + enforces ownership in such a way that once an asset is _moved_, the previous owner completely + loses any control over it. This mechanism ensures a clear and secure change of ownership. -- **Non-copyable:** In the real world, unique items cannot be duplicated effortlessly. Move applies this principle to digital assets, ensuring they cannot be arbitrarily copied within the program. This property is crucial for maintaining the scarcity and uniqueness of digital assets, mirroring the intrinsic value of physical assets. +- **Non-copyable:** In the real world, unique items cannot be duplicated effortlessly. Move applies + this principle to digital assets, ensuring they cannot be arbitrarily copied within the program. + This property is crucial for maintaining the scarcity and uniqueness of digital assets, mirroring + the intrinsic value of physical assets. -- **Non-discardable:** Just as you cannot accidentally lose a house or a car without a trace, Move ensures that no asset can be discarded or lost in a program. Instead, assets must be explicitly transferred or destroyed. This property guarantees the deliberate handling of digital assets, preventing accidental loss and ensuring accountability in asset management. +- **Non-discardable:** Just as you cannot accidentally lose a house or a car without a trace, Move + ensures that no asset can be discarded or lost in a program. Instead, assets must be explicitly + transferred or destroyed. This property guarantees the deliberate handling of digital assets, + preventing accidental loss and ensuring accountability in asset management. -Move managed to encapsulate these properties in its design, becoming an ideal language for digital assets. +Move managed to encapsulate these properties in its design, becoming an ideal language for digital +assets. ## Summary -- Move was designed to provide a first-class abstraction for digital assets, enabling developers to create and manage assets natively. -- Essential properties of digital assets include ownership, non-copyability, and non-discardability, which Move enforces in its design. -- Move's asset model mirrors real-world asset management, ensuring secure and accountable asset ownership and transfer. +- Move was designed to provide a first-class abstraction for digital assets, enabling developers to + create and manage assets natively. +- Essential properties of digital assets include ownership, non-copyability, and non-discardability, + which Move enforces in its design. +- Move's asset model mirrors real-world asset management, ensuring secure and accountable asset + ownership and transfer. ## Further reading -- [Move: A Language With Programmable Resources (pdf)](https://developers.diem.com/papers/diem-move-a-language-with-programmable-resources/2019-06-18.pdf) by Sam Blackshear, Evan Cheng, David L. Dill, Victor Gao, Ben Maurer, Todd Nowacki, Alistair Pott, Shaz Qadeer, Rain, Dario Russi, Stephane Sezer, Tim Zakian, Runtian Zhou* +- [Move: A Language With Programmable Resources (pdf)](https://developers.diem.com/papers/diem-move-a-language-with-programmable-resources/2019-06-18.pdf) + by Sam Blackshear, Evan Cheng, David L. Dill, Victor Gao, Ben Maurer, Todd Nowacki, Alistair Pott, + Shaz Qadeer, Rain, Dario Russi, Stephane Sezer, Tim Zakian, Runtian Zhou\* diff --git a/book/src/object/evolution-of-move.md b/book/src/object/evolution-of-move.md index b93ca92c..113fa8df 100644 --- a/book/src/object/evolution-of-move.md +++ b/book/src/object/evolution-of-move.md @@ -1,15 +1,27 @@ # Evolution of Move -While Move was created to manage digital assets, its initial storage model was bulky and not well-suited for many use cases. For instance, if Alice wanted to transfer an asset X to Bob, Bob had to create a new "empty" resource, and then Alice could transfer asset X to Bob. This process was not intuitive and presented implementation challenges, partly due to the restrictive design of [Diem](https://www.diem.com/en-us). Another drawback of the original design was the lack of built-in support for a "transfer" operation, requiring every module to implement its own storage transfer logic. Additionally, managing heterogeneous collections of assets in a single account was particularly challenging. +While Move was created to manage digital assets, its initial storage model was bulky and not +well-suited for many use cases. For instance, if Alice wanted to transfer an asset X to Bob, Bob had +to create a new "empty" resource, and then Alice could transfer asset X to Bob. This process was not +intuitive and presented implementation challenges, partly due to the restrictive design of +[Diem](https://www.diem.com/en-us). Another drawback of the original design was the lack of built-in +support for a "transfer" operation, requiring every module to implement its own storage transfer +logic. Additionally, managing heterogeneous collections of assets in a single account was +particularly challenging. -Sui addressed these challenges by redesigning the storage and ownership model of objects to more closely resemble real-world object interactions. With a native concept of ownership and *transfer*, Alice can directly transfer asset X to Bob. Furthermore, Bob can maintain a collection of different assets without any preparatory steps. These improvements laid the foundation for the Object Model in Sui. +Sui addressed these challenges by redesigning the storage and ownership model of objects to more +closely resemble real-world object interactions. With a native concept of ownership and _transfer_, +Alice can directly transfer asset X to Bob. Furthermore, Bob can maintain a collection of different +assets without any preparatory steps. These improvements laid the foundation for the Object Model in +Sui. ## Summary -- Move's initial storage model was not well-suited for managing digital assets, requiring complex and restrictive transfer operations. -- Sui introduced the Object Model, which provides a native concept of ownership, simplifying asset management and enabling heterogeneous collections. +- Move's initial storage model was not well-suited for managing digital assets, requiring complex + and restrictive transfer operations. +- Sui introduced the Object Model, which provides a native concept of ownership, simplifying asset + management and enabling heterogeneous collections. ## Further reading - [Why We Created Sui Move](https://blog.sui.io/why-we-created-sui-move/) by Sam Blackshear - diff --git a/book/src/object/fast-path-and-consensus.md b/book/src/object/fast-path-and-consensus.md index bdc6044c..27d8bbf2 100644 --- a/book/src/object/fast-path-and-consensus.md +++ b/book/src/object/fast-path-and-consensus.md @@ -1,31 +1,54 @@ # Fast Path & Consensus -The Object Model allows for variable transaction execution paths, depending on the object's ownership type. The transaction execution path determines how the transaction is processed and validated by the network. In this section, we'll explore the different transaction execution paths in Sui and how they interact with the consensus mechanism. +The Object Model allows for variable transaction execution paths, depending on the object's +ownership type. The transaction execution path determines how the transaction is processed and +validated by the network. In this section, we'll explore the different transaction execution paths +in Sui and how they interact with the consensus mechanism. ## Concurrency Challenge -At its core, blockchain technology faces a fundamental concurrency challenge: multiple parties may try to modify or access the same data simultaneously in a decentralized environment. This requires a system for sequencing and validating transactions to support the network's consistency. Sui addresses this challenge through a consensus mechanism, ensuring all nodes agree on the transactions' sequence and state. +At its core, blockchain technology faces a fundamental concurrency challenge: multiple parties may +try to modify or access the same data simultaneously in a decentralized environment. This requires a +system for sequencing and validating transactions to support the network's consistency. Sui +addresses this challenge through a consensus mechanism, ensuring all nodes agree on the +transactions' sequence and state. -Consider a marketplace scenario where Alice and Bob simultaneously attempt to purchase the same asset. The network must resolve this conflict to prevent double-spending, ensuring that at most one transaction succeeds while the other is rightfully rejected. +Consider a marketplace scenario where Alice and Bob simultaneously attempt to purchase the same +asset. The network must resolve this conflict to prevent double-spending, ensuring that at most one +transaction succeeds while the other is rightfully rejected. ## Fast Path -However, not all transactions require the same level of validation and consensus. For example, if Alice wants to transfer an object that she owns to Bob, the network can process this transaction without sequencing it with respect to all other transactions in the network, as only Alice has the authority to access the object. This is known as the *fast path* execution, where transactions accessing account-owned objects are processed quickly without the need for extensive consensus. No concurrent data access -> simpler challenge -> fast path. +However, not all transactions require the same level of validation and consensus. For example, if +Alice wants to transfer an object that she owns to Bob, the network can process this transaction +without sequencing it with respect to all other transactions in the network, as only Alice has the +authority to access the object. This is known as the _fast path_ execution, where transactions +accessing account-owned objects are processed quickly without the need for extensive consensus. No +concurrent data access -> simpler challenge -> fast path. -Another ownership model that allows for fast path execution is the *immutable state*. Since immutable objects cannot change, transactions involving them can be processed quickly without the need to sequence them. +Another ownership model that allows for fast path execution is the _immutable state_. Since +immutable objects cannot change, transactions involving them can be processed quickly without the +need to sequence them. ## Consensus Path -Transactions that do access shared state - on Sui it is represented with shared objects - require sequencing to ensure that the state is updated and consistented across all nodes. This is known as the execution through *consensus*, where transactions accessing shared objects are subject to the agreement process to maintain network consistency. +Transactions that do access shared state - on Sui it is represented with shared objects - require +sequencing to ensure that the state is updated and consistented across all nodes. This is known as +the execution through _consensus_, where transactions accessing shared objects are subject to the +agreement process to maintain network consistency. ## Objects owned by Objects -Lastly, it is important to mention that objects owned by other objects are subject to the same rules as the parent object. If the parent object is *shared*, the child object is also transitively shared. If the parent object is immutable, the child object is also immutable. +Lastly, it is important to mention that objects owned by other objects are subject to the same rules +as the parent object. If the parent object is _shared_, the child object is also transitively +shared. If the parent object is immutable, the child object is also immutable. ## Summary -- **Fast Path:** Transactions involving account-owned objects or immutable shared state are processed quickly without the need for extensive consensus. -- **Consensus Path:** Transactions involving shared objects require sequencing and consensus to ensure network integrity. +- **Fast Path:** Transactions involving account-owned objects or immutable shared state are + processed quickly without the need for extensive consensus. +- **Consensus Path:** Transactions involving shared objects require sequencing and consensus to + ensure network integrity. - **Objects owned by Objects:** Child objects inherit the ownership model of the parent object. diff --git a/book/src/object/object-model.md b/book/src/object/object-model.md index b35e7d08..13eaa282 100644 --- a/book/src/object/object-model.md +++ b/book/src/object/object-model.md @@ -1,22 +1,38 @@ # What is an Object? -The Object Model in Sui can be viewed as a high-level abstraction representing digital assets as *objects*. These objects have their own type and associated behaviors, a unique identifier, and support native storage operations like *transfer* and *share*. Designed to be intuitive and easy to use, the Object Model enables a wide range of use cases to be implemented with ease. +The Object Model in Sui can be viewed as a high-level abstraction representing digital assets as +_objects_. These objects have their own type and associated behaviors, a unique identifier, and +support native storage operations like _transfer_ and _share_. Designed to be intuitive and easy to +use, the Object Model enables a wide range of use cases to be implemented with ease. Objects in Sui have the following properties: -- **Type:** Every object has a type, defining the structure and behavior of the object. Objects of different types cannot be mixed or used interchangeably, ensuring objects are used correctly according to their type system. +- **Type:** Every object has a type, defining the structure and behavior of the object. Objects of + different types cannot be mixed or used interchangeably, ensuring objects are used correctly + according to their type system. -- **Unique ID:** Each object has a unique identifier, distinguishing it from other objects. This ID is generated upon the object's creation and is immutable. It's used to track and identify objects within the system. +- **Unique ID:** Each object has a unique identifier, distinguishing it from other objects. This ID + is generated upon the object's creation and is immutable. It's used to track and identify objects + within the system. -- **Owner:** Every object is associated with an owner, who has control over the object. Ownership on Sui can be exclusive to an account, shared across the network, or frozen, allowing read-only access without modification or transfer capabilities. We will discuss ownership in more detail in the following sections. +- **Owner:** Every object is associated with an owner, who has control over the object. Ownership on + Sui can be exclusive to an account, shared across the network, or frozen, allowing read-only + access without modification or transfer capabilities. We will discuss ownership in more detail in + the following sections. -- **Data:** Objects encapsulate their data, simplifying management and manipulation. The data structure and operations are defined by the object's type. +- **Data:** Objects encapsulate their data, simplifying management and manipulation. The data + structure and operations are defined by the object's type. -- **Version:** The transition from accounts to objects is facilitated by object versioning. Traditionally, blockchains use a *nonce* to prevent replay attacks. In Sui, the object's version acts as a nonce, preventing replay attacks for each object. +- **Version:** The transition from accounts to objects is facilitated by object versioning. + Traditionally, blockchains use a _nonce_ to prevent replay attacks. In Sui, the object's version + acts as a nonce, preventing replay attacks for each object. -- **Digest:** Every object has a digest, which is a hash of the object's data. The digest is used to cryptographically verify the integrity of the object's data and ensures that it has not been tampered with. The digest is calculated when the object is created and is updated whenever the object's data changes. +- **Digest:** Every object has a digest, which is a hash of the object's data. The digest is used to + cryptographically verify the integrity of the object's data and ensures that it has not been + tampered with. The digest is calculated when the object is created and is updated whenever the + object's data changes. ## Summary diff --git a/book/src/object/ownership.md b/book/src/object/ownership.md index 93110345..2920f00e 100644 --- a/book/src/object/ownership.md +++ b/book/src/object/ownership.md @@ -1,37 +1,69 @@ # Ownership -Sui introduces four distinct ownership types for objects: single owner, shared state, immutable shared state, and object-owner. Each model offers unique characteristics and suits different use cases, enhancing flexibility and control in object management. - +Sui introduces four distinct ownership types for objects: single owner, shared state, immutable +shared state, and object-owner. Each model offers unique characteristics and suits different use +cases, enhancing flexibility and control in object management. ## Account Owner (or Single Owner) -The account owner, also known as the *single owner* model, is the foundational ownership type in Sui. Here, an object is owned by a single account, granting that account exclusive control over the object within the behaviors associated with its type. This model embodies the concept of *true ownership*, where the account possesses complete authority over the object, making it inaccessible to others for modification or transfer. This level of ownership clarity is a significant advantage over other blockchain systems, where ownership definitions can be more ambiguous, and smart contracts may have the ability to alter or transfer assets without the owner's consent. +The account owner, also known as the _single owner_ model, is the foundational ownership type in +Sui. Here, an object is owned by a single account, granting that account exclusive control over the +object within the behaviors associated with its type. This model embodies the concept of _true +ownership_, where the account possesses complete authority over the object, making it inaccessible +to others for modification or transfer. This level of ownership clarity is a significant advantage +over other blockchain systems, where ownership definitions can be more ambiguous, and smart +contracts may have the ability to alter or transfer assets without the owner's consent. ## Shared State -Single owner model has its limitations: for example, it is very tricky to implement a marketplace for digital assets without a shared state. For a generic marketplace scenario, imagine that Alice owns an asset X, and she wants to sell it by putting it into a shared marketplace. Then Bob can come and buy the asset directly from the marketplace. The reason why this is tricky is that it is impossible to write a smart contract that would "lock" the asset in Alice's account and take it out when Bob buys it. First, it will be a violation of the single owner model, and second, it requires a shared access to the asset. +Single owner model has its limitations: for example, it is very tricky to implement a marketplace +for digital assets without a shared state. For a generic marketplace scenario, imagine that Alice +owns an asset X, and she wants to sell it by putting it into a shared marketplace. Then Bob can come +and buy the asset directly from the marketplace. The reason why this is tricky is that it is +impossible to write a smart contract that would "lock" the asset in Alice's account and take it out +when Bob buys it. First, it will be a violation of the single owner model, and second, it requires a +shared access to the asset. -To facilitate a problem of shared data access, Sui has introduced a shared ownership model. In this model, an object can be shared with the network. Shared objects can be read and modified by any account on the network, and the rules of interaction are defined by the implementation of the object. Typical uses for shared objects are: marketplaces, shared resources, escrows, and other scenarios where multiple accounts need access to the same state. +To facilitate a problem of shared data access, Sui has introduced a shared ownership model. In this +model, an object can be shared with the network. Shared objects can be read and modified by any +account on the network, and the rules of interaction are defined by the implementation of the +object. Typical uses for shared objects are: marketplaces, shared resources, escrows, and other +scenarios where multiple accounts need access to the same state. ## Immutable (Frozen) State -Sui also offers the *frozen object* model, where an object becomes permanently read-only. These immutable objects, while readable, cannot be modified or moved, providing a stable and constant state accessible to all network participants. Frozen objects are ideal for public data, reference materials, and other use cases where the state permanence is desirable. +Sui also offers the _frozen object_ model, where an object becomes permanently read-only. These +immutable objects, while readable, cannot be modified or moved, providing a stable and constant +state accessible to all network participants. Frozen objects are ideal for public data, reference +materials, and other use cases where the state permanence is desirable. ## Object Owner -The last ownership model in Sui is the *object owner*. In this model, an object is owned by another object. This feature allows creating complex relationships between objects, store large heterogenious collections, and implementing extensible and modular systems. Practically speaking, since the transactions are initiated by accounts, the transaction still accesses the parent object, but it can then access the child objects through the parent object. +The last ownership model in Sui is the _object owner_. In this model, an object is owned by another +object. This feature allows creating complex relationships between objects, store large +heterogenious collections, and implementing extensible and modular systems. Practically speaking, +since the transactions are initiated by accounts, the transaction still accesses the parent object, +but it can then access the child objects through the parent object. -A use case we love to mention is a game character. Alice can own the Hero object from a game, and the Hero can own items: also represented as objects, like a "Map", or a "Compass". Alice may take the "Map" from the "Hero" object, and then send it to Bob, or sell it on a marketplace. With object owner, it becomes very natural to imagine how the assets can be structured and managed in relation to each other. +A use case we love to mention is a game character. Alice can own the Hero object from a game, and +the Hero can own items: also represented as objects, like a "Map", or a "Compass". Alice may take +the "Map" from the "Hero" object, and then send it to Bob, or sell it on a marketplace. With object +owner, it becomes very natural to imagine how the assets can be structured and managed in relation +to each other. ## Summary -- **Single Owner:** Objects are owned by a single account, granting exclusive control over the object. -- **Shared State:** Objects can be shared with the network, allowing multiple accounts to read and modify the object. +- **Single Owner:** Objects are owned by a single account, granting exclusive control over the + object. +- **Shared State:** Objects can be shared with the network, allowing multiple accounts to read and + modify the object. - **Immutable State:** Objects become permanently read-only, providing a stable and constant state. -- **Object Owner:** Objects can own other objects, enabling complex relationships and modular systems. +- **Object Owner:** Objects can own other objects, enabling complex relationships and modular + systems. ## Next Steps -In the next section we will talk about transaction execution paths in Sui, and how the ownership models affect the transaction execution. +In the next section we will talk about transaction execution paths in Sui, and how the ownership +models affect the transaction execution. diff --git a/book/src/programmability/README.md b/book/src/programmability/README.md index c0e20d2e..e3b857cc 100644 --- a/book/src/programmability/README.md +++ b/book/src/programmability/README.md @@ -1,5 +1,10 @@ # Advanced Programmability -In previous chapters we've covered [the basics of Move](./../move-basics/README.md) and [Sui Storage Model](./../programmability/README.md). Now it's time to dive deeper into the advanced topics of Sui programmability. +In previous chapters we've covered [the basics of Move](./../move-basics/README.md) and +[Sui Storage Model](./../programmability/README.md). Now it's time to dive deeper into the advanced +topics of Sui programmability. -This chapter introduces more complex concepts, practices and features of Move and Sui that are essential for building more sophisticated applications. It is intended for developers who are already familiar with the basics of Move and Sui, and are looking to expand their knowledge and skills. +This chapter introduces more complex concepts, practices and features of Move and Sui that are +essential for building more sophisticated applications. It is intended for developers who are +already familiar with the basics of Move and Sui, and are looking to expand their knowledge and +skills. diff --git a/book/src/programmability/abstract-class.md b/book/src/programmability/abstract-class.md deleted file mode 100644 index 5a18b55e..00000000 --- a/book/src/programmability/abstract-class.md +++ /dev/null @@ -1,41 +0,0 @@ -# Abstract Class - - - -Some of the language features combined together can create patterns that are similar to other programming languages. The simplest example would be "getters and setters" - functions that get and set the value of a field. This pattern is possible, because struct fields are private by default, and can only be accessed through functions. - -However, there are more advanced patterns, such as the abstract class. An abstract class is a class that cannot be instantiated, but can be inherited from. While Move does not have inheritance, it has generic structs, which can be instantiated with different types. This allows us to create a generic struct that can be used as an abstract class. Combined with a set of Witness-gated functions, this allows us to create a generic struct with a generic implementation. - -Some of the methods in this approach will be shared and available to all implementations, while others will be abstract and will need to be implemented by the concrete implementations. - -## Generic Struct - - - -## Common methods - - - -## Witness-gated Functions - - - -## Differences from OOP - -While this approach imitates the abstract class pattern well, it is not the same as the abstract class in OOP. The main difference is that the abstract class in OOP and its implementors have different type. In Move, the base type stays the same, and the implementors set a generic type parameter. Another notable difference is that due to lack of dynamic dispatch and interfaces, the implemented methods are not available through the base type and can even be missing. - -## Usage in Sui Framework - -The Sui Framework uses this pattern to implement the `Coin` type and the underlying `Balance`. Its variation is also used in the Closed Loop Token implementation, however, the latter is a bit more complex, because it uses the Request pattern to dynamically implement the interface. diff --git a/book/src/programmability/bcs.md b/book/src/programmability/bcs.md index c1da140d..96a75e8f 100644 --- a/book/src/programmability/bcs.md +++ b/book/src/programmability/bcs.md @@ -1,12 +1,16 @@ # Binary Canonical Serialization -Binary Canonical Serialization (BCS) is a binary encoding format for structured data. It is designed to be simple, efficient, and deterministic. BCS is used in Sui and Move to serialize and deserialize data structures. +Binary Canonical Serialization (BCS) is a binary encoding format for structured data. It is designed +to be simple, efficient, and deterministic. BCS is used in Sui and Move to serialize and deserialize +data structures. The format specification is available in the [BCS repository](https://github.com/zefchain/bcs). ## Using BCS -[Standard Library](./../move-basics/standard-library.md) provides the `std::bcs` module that contains functions for encoding and decoding data using BCS. The module has one function for getting data bytes for any type: +[Standard Library](./../move-basics/standard-library.md) provides the `std::bcs` module that +contains functions for encoding and decoding data using BCS. The module has one function for getting +data bytes for any type: File: move-stdlib/sources/bcs.move @@ -14,7 +18,8 @@ File: move-stdlib/sources/bcs.move public native fun to_bytes(t: &T): vector; ``` -[Sui Framework](./../sui-framework.md) offers its own module `sui::bcs` which allows both encoding and decoding data. Decoding is implemented in Move, without the need for a native function. +[Sui Framework](./../sui-framework.md) offers its own module `sui::bcs` which allows both encoding +and decoding data. Decoding is implemented in Move, without the need for a native function. ```move {{#include ../../../packages/samples/sources/programmability/bcs.move:using_bcs}} diff --git a/book/src/programmability/capability.md b/book/src/programmability/capability.md index 2a06748b..4fd775ee 100644 --- a/book/src/programmability/capability.md +++ b/book/src/programmability/capability.md @@ -1,12 +1,20 @@ # Pattern: Capability -In programming, a _capability_ is a token that gives the owner the right to perform a specific action. It is a pattern that is used to control access to resources and operations. A simple example of a capability is a key to a door. If you have the key, you can open the door. If you don't have the key, you can't open the door. A more practical example is an Admin Capability which allows the owner to perform administrative operations, which regular users cannot. +In programming, a _capability_ is a token that gives the owner the right to perform a specific +action. It is a pattern that is used to control access to resources and operations. A simple example +of a capability is a key to a door. If you have the key, you can open the door. If you don't have +the key, you can't open the door. A more practical example is an Admin Capability which allows the +owner to perform administrative operations, which regular users cannot. ## Capability is an Object -In the [Sui Object Model](./../concepts/object-model.md), capabilities are represented as objects. An owner of an object can pass this object to a function to prove that they have the right to perform a specific action. Due to strict typing, the function taking a capability as an argument can only be called with the correct capability. +In the [Sui Object Model](./../concepts/object-model.md), capabilities are represented as objects. +An owner of an object can pass this object to a function to prove that they have the right to +perform a specific action. Due to strict typing, the function taking a capability as an argument can +only be called with the correct capability. -> There's a convention to name capabilities with the `Cap` suffix, for example, `AdminCap` or `KioskOwnerCap`. +> There's a convention to name capabilities with the `Cap` suffix, for example, `AdminCap` or +> `KioskOwnerCap`. ```move {{#include ../../../packages/samples/sources/programmability/capability.move:main}} @@ -14,7 +22,8 @@ In the [Sui Object Model](./../concepts/object-model.md), capabilities are repre ## Using `init` for Admin Capability -A very common practice is to create a single `AdminCap` object on package publish. This way, the application can have a setup phase where the admin account prepares the state of the application. +A very common practice is to create a single `AdminCap` object on package publish. This way, the +application can have a setup phase where the admin account prepares the state of the application. ```move {{#include ../../../packages/samples/sources/programmability/capability.move:admin_cap}} @@ -22,9 +31,13 @@ A very common practice is to create a single `AdminCap` object on package publis ## Address check vs Capability -Utilizing objects as capabilities is a relatively new concept in blockchain programming. And in other smart-contract languages, authorization is often performed by checking the address of the sender. This pattern is still viable on Sui, however, overall recommendation is to use capabilities for better security, discoverability, and code organization. +Utilizing objects as capabilities is a relatively new concept in blockchain programming. And in +other smart-contract languages, authorization is often performed by checking the address of the +sender. This pattern is still viable on Sui, however, overall recommendation is to use capabilities +for better security, discoverability, and code organization. -Let's look at how the `new` function that creates a user would look like if it was using the address check: +Let's look at how the `new` function that creates a user would look like if it was using the address +check: ```move {{#include ../../../packages/samples/sources/programmability/capability.move:with_address}} @@ -38,9 +51,19 @@ And now, let's see how the same function would look like with the capability: Using capabilities has several advantages over the address check: -- Migration of admin rights is easier with capabilities due to them being objects. In case of address, if the admin address changes, all the functions that check the address need to be updated - hence, require a [package upgrade](./package-upgrades.md). -- Function signatures are more descriptive with capabilities. It is clear that the `new` function requires the `AdminCap` to be passed as an argument. And this function can't be called without it. -- Object Capabilities don't require extra checks in the function body, and hence, decrease the chance of a developer mistake. -- An owned Capability also serves in discovery. The owner of the AdminCap can see the object in their account (via a Wallet or Explorer), and know that they have the admin rights. This is less transparent with the address check. - -However, the address approach has its own advantages. For example, if an address is multisig, and transaction building gets more complex, it might be easier to check the address. Also, if there's a central object of the application that is used in every function, it can store the admin address, and this would simplify migration. The central object approach is also valuable for revokable capabilities, where the admin can revoke the capability from the user. +- Migration of admin rights is easier with capabilities due to them being objects. In case of + address, if the admin address changes, all the functions that check the address need to be + updated - hence, require a [package upgrade](./package-upgrades.md). +- Function signatures are more descriptive with capabilities. It is clear that the `new` function + requires the `AdminCap` to be passed as an argument. And this function can't be called without it. +- Object Capabilities don't require extra checks in the function body, and hence, decrease the + chance of a developer mistake. +- An owned Capability also serves in discovery. The owner of the AdminCap can see the object in + their account (via a Wallet or Explorer), and know that they have the admin rights. This is less + transparent with the address check. + +However, the address approach has its own advantages. For example, if an address is multisig, and +transaction building gets more complex, it might be easier to check the address. Also, if there's a +central object of the application that is used in every function, it can store the admin address, +and this would simplify migration. The central object approach is also valuable for revokable +capabilities, where the admin can revoke the capability from the user. diff --git a/book/src/programmability/collections.md b/book/src/programmability/collections.md index d53bf731..03c8e06a 100644 --- a/book/src/programmability/collections.md +++ b/book/src/programmability/collections.md @@ -1,10 +1,16 @@ # Collections -Collection types are a fundamental part of any programming language. They are used to store a collection of data, such as a list of items. The `vector` type has already been covered in the [vector section](./../move-basics/vector.md), and in this chapter we will cover the vector-based collection types offered by the [Sui Framework](./sui-framework.md). +Collection types are a fundamental part of any programming language. They are used to store a +collection of data, such as a list of items. The `vector` type has already been covered in the +[vector section](./../move-basics/vector.md), and in this chapter we will cover the vector-based +collection types offered by the [Sui Framework](./sui-framework.md). ## Vector -While we have previously covered the `vector` type in the [vector section](./../move-basics/vector.md), it is worth going over it again in a new context. This time we will cover the usage of the `vector` type in objects and how it can be used in an application. +While we have previously covered the `vector` type in the +[vector section](./../move-basics/vector.md), it is worth going over it again in a new context. This +time we will cover the usage of the `vector` type in objects and how it can be used in an +application. ```move {{#include ../../../packages/samples/sources/programmability/collections.move:vector}} @@ -12,7 +18,9 @@ While we have previously covered the `vector` type in the [vector section](./../ ## VecSet -`VecSet` is a collection type that stores a set of unique items. It is similar to a `vector`, but it does not allow duplicate items. This makes it useful for storing a collection of unique items, such as a list of unique IDs or addresses. +`VecSet` is a collection type that stores a set of unique items. It is similar to a `vector`, but it +does not allow duplicate items. This makes it useful for storing a collection of unique items, such +as a list of unique IDs or addresses. ```move {{#include ../../../packages/samples/sources/programmability/collections.move:vec_set}} @@ -22,9 +30,14 @@ VecSet will fail on attempt to insert a an item that already exists in the set. ## VecMap -`VecMap` is a collection type that stores a map of key-value pairs. It is similar to a `VecSet`, but it allows you to associate a value with each item in the set. This makes it useful for storing a collection of key-value pairs, such as a list of addresses and their balances, or a list of user IDs and their associated data. +`VecMap` is a collection type that stores a map of key-value pairs. It is similar to a `VecSet`, but +it allows you to associate a value with each item in the set. This makes it useful for storing a +collection of key-value pairs, such as a list of addresses and their balances, or a list of user IDs +and their associated data. -Keys in a `VecMap` are unique, and each key can only be associated with a single value. If you try to insert a key-value pair with a key that already exists in the map, the old value will be replaced with the new value. +Keys in a `VecMap` are unique, and each key can only be associated with a single value. If you try +to insert a key-value pair with a key that already exists in the map, the old value will be replaced +with the new value. ```move {{#include ../../../packages/samples/sources/programmability/collections.move:vec_map}} @@ -32,28 +45,37 @@ Keys in a `VecMap` are unique, and each key can only be associated with a single ## Limitations -Standard collection types are a great way to store typed data with guaranteed safety and consistency. However, they are limited by the type of data they can store - the type system won't allow you to store a wrong type in a collection; and they're limited in size - by the object size limit. They will work for relatively small-sized sets and lists, but for larger collections you may need to use a different approach. +Standard collection types are a great way to store typed data with guaranteed safety and +consistency. However, they are limited by the type of data they can store - the type system won't +allow you to store a wrong type in a collection; and they're limited in size - by the object size +limit. They will work for relatively small-sized sets and lists, but for larger collections you may +need to use a different approach. -Another limitations on collection types is inability to compare them. Because the order of insertion is not guaranteed, an attempt to compare a `VecSet` to another `VecSet` may not yield the expected results. +Another limitations on collection types is inability to compare them. Because the order of insertion +is not guaranteed, an attempt to compare a `VecSet` to another `VecSet` may not yield the expected +results. -> This behavior is caught by the linter and will emit a warning: -> *Comparing collections of type 'sui::vec_set::VecSet' may yield unexpected result* +> This behavior is caught by the linter and will emit a warning: _Comparing collections of type +> 'sui::vec_set::VecSet' may yield unexpected result_ ```move {{#include ../../../packages/samples/sources/programmability/collections.move:vec_set_comparison}} ``` -In the example above, the comparison will fail because the order of insertion is not guaranteed, and the two `VecSet` instances may have different orders of elements. And the comparison will fail even if the two `VecSet` instances contain the same elements. - - +In the example above, the comparison will fail because the order of insertion is not guaranteed, and +the two `VecSet` instances may have different orders of elements. And the comparison will fail even +if the two `VecSet` instances contain the same elements. ## Summary - Vector is a native type that allows storing a list of items. - VecSet is built on top of vector and allows storing sets of unique items. - VecMap is used to store key-value pairs in a map-like structure. -- Vector-based collections are strictly typed and limited by the object size limit and are best suited for small-sized sets and lists. +- Vector-based collections are strictly typed and limited by the object size limit and are best + suited for small-sized sets and lists. ## Next Steps -In the next section we will cover [Dynamic Fields](./dynamic-fields.md) - an important primitive that allows for [Dynamic Collections](./dynamic-collections.md) - a way to store large collections of data in a more flexible, yet more expensive way. +In the next section we will cover [Dynamic Fields](./dynamic-fields.md) - an important primitive +that allows for [Dynamic Collections](./dynamic-collections.md) - a way to store large collections +of data in a more flexible, yet more expensive way. diff --git a/book/src/programmability/display.md b/book/src/programmability/display.md index fb41a1bb..8b0ac112 100644 --- a/book/src/programmability/display.md +++ b/book/src/programmability/display.md @@ -1,24 +1,39 @@ # Object Display -Objects on Sui are explicit in their structure and behavior and can be displayed in an understandable way. However, to support richer metadata for clients, there's a standard and efficient way of "describing" them to the client - the `Display` object defined in the [Sui Framework](./sui-framework.md). +Objects on Sui are explicit in their structure and behavior and can be displayed in an +understandable way. However, to support richer metadata for clients, there's a standard and +efficient way of "describing" them to the client - the `Display` object defined in the +[Sui Framework](./sui-framework.md). ## Background -Historically, there were different attempts to agree on a standard structure of an object so it can be displayed in a user interface. One of the approaches was to define certain fields in the object struct which, when present, would be used in the UI. This approach was not flexible enough and required developers to define the same fields in every object, and sometimes the fields did not make sense for the object. +Historically, there were different attempts to agree on a standard structure of an object so it can +be displayed in a user interface. One of the approaches was to define certain fields in the object +struct which, when present, would be used in the UI. This approach was not flexible enough and +required developers to define the same fields in every object, and sometimes the fields did not make +sense for the object. ```move {{#include ../../../packages/samples/sources/programmability/display.move:background}} ``` -If any of the fields contained static data, it would be duplicated in every object. And, since Move does not have interfaces, it is not possible to know if an object has a specific field without "manually" checking the object's type, which makes the client fetching more complex. +If any of the fields contained static data, it would be duplicated in every object. And, since Move +does not have interfaces, it is not possible to know if an object has a specific field without +"manually" checking the object's type, which makes the client fetching more complex. ## Object Display -To address these issues, Sui introduces a standard way of describing an object for display. Instead of defining fields in the object struct, the display metadata is stored in a separate object, which is associated with the type. This way, the display metadata is not duplicated, and it is easy to extend and maintain. +To address these issues, Sui introduces a standard way of describing an object for display. Instead +of defining fields in the object struct, the display metadata is stored in a separate object, which +is associated with the type. This way, the display metadata is not duplicated, and it is easy to +extend and maintain. -Another important feature of Sui Display is the ability to define templates and use object fields in those templates. Not only it allows for a more flexible display, but it also frees the developer from the need to define the same fields with the same names and types in every object. +Another important feature of Sui Display is the ability to define templates and use object fields in +those templates. Not only it allows for a more flexible display, but it also frees the developer +from the need to define the same fields with the same names and types in every object. -> The Object Display is natively supported by the Sui Fullnode, and the client can fetch the display metadata for any object if the object type has a Display associated with it. +> The Object Display is natively supported by the Sui Fullnode, and the client can fetch the display +> metadata for any object if the object type has a Display associated with it. ```move {{#include ../../../packages/samples/sources/programmability/display.move:hero}} @@ -26,27 +41,40 @@ Another important feature of Sui Display is the ability to define templates and ## Creator Privilege -While the objects can be owned by accounts and may be a subject to [True Ownership](./../object/true-ownership.md), the Display can be owned by the creator of the object. This way, the creator can update the display metadata and apply the changes globally without the need to update every object. The creator can also transfer Display to another account or even build an application around the object with custom functionality to manage the metadata. +While the objects can be owned by accounts and may be a subject to +[True Ownership](./../object/true-ownership.md), the Display can be owned by the creator of the +object. This way, the creator can update the display metadata and apply the changes globally without +the need to update every object. The creator can also transfer Display to another account or even +build an application around the object with custom functionality to manage the metadata. ## Standard Fields The fields that are supported most widely are: - `name` - A name for the object. The name is displayed when users view the object. -- `description` - A description for the object. The description is displayed when users view the object. +- `description` - A description for the object. The description is displayed when users view the + object. - `link` - A link to the object to use in an application. - `image_url` - A URL or a blob with the image for the object. -- `thumbnail_url` - A URL to a smaller image to use in wallets, explorers, and other products as a preview. +- `thumbnail_url` - A URL to a smaller image to use in wallets, explorers, and other products as a + preview. - `project_url` - A link to a website associated with the object or creator. - `creator` - A string that indicates the object creator. -> Please, refer to the [Sui Documentation](https://docs.sui.io/standards/display) for the most up-to-date list of supported fields. +> Please, refer to the [Sui Documentation](https://docs.sui.io/standards/display) for the most +> up-to-date list of supported fields. -While there's a standard set of fields, the Display object does not enforce them. The developer can define any fields they need, and the client can use them as they see fit. Some applications may require additional fields, and omit other, and the Display is flexible enough to support them. +While there's a standard set of fields, the Display object does not enforce them. The developer can +define any fields they need, and the client can use them as they see fit. Some applications may +require additional fields, and omit other, and the Display is flexible enough to support them. ## Working with Display -The `Display` object is defined in the `sui::display` module. It is a generic struct that takes a phantom type as a parameter. The phantom type is used to associate the `Display` object with the type it describes. The `fields` of the `Display` object are a `VecMap` of key-value pairs, where the key is the field name and the value is the field value. The `version` field is used to version the display metadata, and is updated on the `update_display` call. +The `Display` object is defined in the `sui::display` module. It is a generic struct that takes a +phantom type as a parameter. The phantom type is used to associate the `Display` object with the +type it describes. The `fields` of the `Display` object are a `VecMap` of key-value pairs, where the +key is the field name and the value is the field value. The `version` field is used to version the +display metadata, and is updated on the `update_display` call. File: sui-framework/sources/display.move @@ -61,11 +89,14 @@ struct Display has key, store { } ``` -The [Publisher](./publisher.md) object is required to a new Display, since it serves as the proof of ownership of type. +The [Publisher](./publisher.md) object is required to a new Display, since it serves as the proof of +ownership of type. ## Template Syntax -Currently, Display supports simple string interpolation and can use struct fields (and paths) in its templates. The syntax is trivial - `{path}` is replaced with the value of the field at the path. The path is a dot-separated list of field names, starting from the root object in case of nested fields. +Currently, Display supports simple string interpolation and can use struct fields (and paths) in its +templates. The syntax is trivial - `{path}` is replaced with the value of the field at the path. The +path is a dot-separated list of field names, starting from the root object in case of nested fields. ```move {{#include ../../../packages/samples/sources/programmability/display.move:nested}} @@ -83,7 +114,8 @@ The Display for the type `LittlePony` above could be defined as follows: ## Multiple Display Objects -There's no restriction to how many `Display` objects can be created for a specific `T`. However, the most recently updated `Display` will be used by the fullnode. +There's no restriction to how many `Display` objects can be created for a specific `T`. However, +the most recently updated `Display` will be used by the fullnode. ## Further Reading diff --git a/book/src/programmability/dynamic-fields.md b/book/src/programmability/dynamic-fields.md index 050069f1..eb29ee42 100644 --- a/book/src/programmability/dynamic-fields.md +++ b/book/src/programmability/dynamic-fields.md @@ -1,14 +1,23 @@ # Dynamic Fields -Sui Object model allows objects to be attached to other objects as _dynamic fields_. The behavior is similar to how a `Map` works in other programming languages. However, unlike a `Map` which in Move would be strictly typed (we have covered it in the [Collections](./collections.md) section), dynamic fields allow attaching objects of any type. A similar approach from the world of frontend development would be a JavaScript Object type which allows storing any type of data dynamically. +Sui Object model allows objects to be attached to other objects as _dynamic fields_. The behavior is +similar to how a `Map` works in other programming languages. However, unlike a `Map` which in Move +would be strictly typed (we have covered it in the [Collections](./collections.md) section), dynamic +fields allow attaching objects of any type. A similar approach from the world of frontend +development would be a JavaScript Object type which allows storing any type of data dynamically. -> There's no limit to the number of dynamic fields that can be attached to an object. Thus, dynamic fields can be used to store large amounts of data that don't fit into the object limit size. +> There's no limit to the number of dynamic fields that can be attached to an object. Thus, dynamic +> fields can be used to store large amounts of data that don't fit into the object limit size. -Dynamic Fields allow for a wide range of applications, from splitting data into smaller parts to avoid [object size limit](./../guides/building-against-limits.md) to attaching objects as a part of application logic. +Dynamic Fields allow for a wide range of applications, from splitting data into smaller parts to +avoid [object size limit](./../guides/building-against-limits.md) to attaching objects as a part of +application logic. ## Definition -Dynamic Fields are defined in the `sui::dynamic_field` module of the [Sui Framework](./sui-framework.md). They are attached to object's `UID` via a _name_, and can be accessed using that name. There can be only one field with a given name attached to an object. +Dynamic Fields are defined in the `sui::dynamic_field` module of the +[Sui Framework](./sui-framework.md). They are attached to object's `UID` via a _name_, and can be +accessed using that name. There can be only one field with a given name attached to an object. File: sui-framework/sources/dynamic_field.move @@ -25,80 +34,124 @@ public struct Field has key { } ``` -As the definition shows, dynamic fields are stored in an internal `Field` object, which has the `UID` generated in a deterministic way based on the object ID, the field name, and the field type. The `Field` object contains the field name and the value bound to it. The constraints on the `Name` and `Value` type parameters define the abilities that the key and value must have. +As the definition shows, dynamic fields are stored in an internal `Field` object, which has the +`UID` generated in a deterministic way based on the object ID, the field name, and the field type. +The `Field` object contains the field name and the value bound to it. The constraints on the `Name` +and `Value` type parameters define the abilities that the key and value must have. ## Usage -The methods available for dynamic fields are straightforward: a field can be added with `add`, removed with `remove`, and read with `borrow` and `borrow_mut`. Additionally, the `exists_` method can be used to check if a field exists (for stricter checks with type, there is an `exists_with_type` method). +The methods available for dynamic fields are straightforward: a field can be added with `add`, +removed with `remove`, and read with `borrow` and `borrow_mut`. Additionally, the `exists_` method +can be used to check if a field exists (for stricter checks with type, there is an +`exists_with_type` method). ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:usage}} } ``` -In the example above, we define a `Character` object and two different types of accessories that could never be put together in a vector. However, dynamic fields allow us to store them together in a single object. Both objects are attached to the `Character` via a `vector` (bytestring literal), and can be accessed using their respective keys. +In the example above, we define a `Character` object and two different types of accessories that +could never be put together in a vector. However, dynamic fields allow us to store them together in +a single object. Both objects are attached to the `Character` via a `vector` (bytestring +literal), and can be accessed using their respective keys. -As you can see, when we attached the accessories to the Character, we passed them _by value_. In other words, both values were moved to a new scope, and their ownership was transferred to the `Character` object. If we changed the ownership of `Character` object, the accessories would have been moved with it. +As you can see, when we attached the accessories to the Character, we passed them _by value_. In +other words, both values were moved to a new scope, and their ownership was transferred to the +`Character` object. If we changed the ownership of `Character` object, the accessories would have +been moved with it. -And the last important property of dynamic fields we should highlight is that they are _accessed through their parent_. This means that the `Hat` and `Mustache` objects are not directly accessible and follow the same rules as the parent object. +And the last important property of dynamic fields we should highlight is that they are _accessed +through their parent_. This means that the `Hat` and `Mustache` objects are not directly accessible +and follow the same rules as the parent object. ## Foreign Types as Dynamic Fields -Dynamic fields allow objects to carry data of any type, including those defined in other modules. This is possible due to their generic nature and relatively weak constraints on the type parameters. Let's illustrate this by attaching a few different values to a `Character` object. +Dynamic fields allow objects to carry data of any type, including those defined in other modules. +This is possible due to their generic nature and relatively weak constraints on the type parameters. +Let's illustrate this by attaching a few different values to a `Character` object. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:foreign_types}} ``` -In this example we showed how different types can be used for both _name_ and the _value_ of a dynamic field. The `String` is attached via a `vector` name, the `u64` is attached via a `u32` name, and the `bool` is attached via a `bool` name. Anything is possible with dynamic fields! +In this example we showed how different types can be used for both _name_ and the _value_ of a +dynamic field. The `String` is attached via a `vector` name, the `u64` is attached via a `u32` +name, and the `bool` is attached via a `bool` name. Anything is possible with dynamic fields! ## Orphaned Dynamic Fields -> To prevent orphaned dynamic fields, please, use [Dynamic Collection Types](./dynamic-collections.md) such as `Bag` as they track the dynamic fields and won't allow unpacking if there are attached fields. +> To prevent orphaned dynamic fields, please, use +> [Dynamic Collection Types](./dynamic-collections.md) such as `Bag` as they track the dynamic +> fields and won't allow unpacking if there are attached fields. -The `object::delete()` function, which is used to delete a UID, does not track the dynamic fields, and cannot prevent dynamic fields from becoming orphaned. Once the parent UID is deleted, the dynamic fields are not automatically deleted, and they become orphaned. This means that the dynamic fields are still stored in the blockchain, but they will never become accessible again. +The `object::delete()` function, which is used to delete a UID, does not track the dynamic fields, +and cannot prevent dynamic fields from becoming orphaned. Once the parent UID is deleted, the +dynamic fields are not automatically deleted, and they become orphaned. This means that the dynamic +fields are still stored in the blockchain, but they will never become accessible again. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:orphan_fields}} ``` -Orphaned objects are not a subject to storage rebate, and the storage fees will remain unclaimed. One way to avoid orphaned dynamic fields during unpacking on an object is to return the `UID` and store it somewhere temporarily until the dynamic fields are removed and handled properly. +Orphaned objects are not a subject to storage rebate, and the storage fees will remain unclaimed. +One way to avoid orphaned dynamic fields during unpacking on an object is to return the `UID` and +store it somewhere temporarily until the dynamic fields are removed and handled properly. ## Custom Type as a Field Name -In the examples above, we used primitive types as field names since they have the required set of abilities. But dynamic fields get even more interesting when we use custom types as field names. This allows for a more structured way of storing data, and also allows for protecting the field names from being accessed by other modules. +In the examples above, we used primitive types as field names since they have the required set of +abilities. But dynamic fields get even more interesting when we use custom types as field names. +This allows for a more structured way of storing data, and also allows for protecting the field +names from being accessed by other modules. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:custom_type}} ``` -Two field names that we defined above are `AccessoryKey` and `MetadataKey`. The `AccessoryKey` has a `String` field in it, hence it can be used multiple times with different `name` values. The `MetadataKey` is an empty key, and can be attached only once. +Two field names that we defined above are `AccessoryKey` and `MetadataKey`. The `AccessoryKey` has a +`String` field in it, hence it can be used multiple times with different `name` values. The +`MetadataKey` is an empty key, and can be attached only once. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:custom_type_usage}} ``` -As you can see, custom types do work as field names but as long as they can be _constructed_ by the module, in other words - if they are _internal_ to the module and defined in it. This limitation on struct packing can open up new ways in the design of the application. +As you can see, custom types do work as field names but as long as they can be _constructed_ by the +module, in other words - if they are _internal_ to the module and defined in it. This limitation on +struct packing can open up new ways in the design of the application. -This approach is used in the [Object Capability]() pattern, where an application can authorize a foreign object to perform operations in it while not exposing the capabilities to other modules. +This approach is used in the [Object Capability]() pattern, where an application can authorize a +foreign object to perform operations in it while not exposing the capabilities to other modules. ## Exposing UID
-Mutable access to `UID` is a security risk. Exposing `UID` of your type as a mutable reference can lead to unwanted modifications or removal of the object's dynamic fields. Additionally, it affects the [Transfer to Object](./../storage/transfer-to-object.md) and [Dynamic Object Fields](./dynamic-object-fields.md). Make sure to understand the implications before exposing the `UID` as a mutable reference. +Mutable access to `UID` is a security risk. Exposing `UID` of your type as a mutable reference can +lead to unwanted modifications or removal of the object's dynamic fields. Additionally, it affects +the [Transfer to Object](./../storage/transfer-to-object.md) and +[Dynamic Object Fields](./dynamic-object-fields.md). Make sure to understand the implications before +exposing the `UID` as a mutable reference.
-Because dynamic fields are attached to `UID`s, their usage in other modules depends on whether the `UID` can be accessed. By default struct visibility protects the `id` field and won't let other modules access it directly. However, if there's a public accessor method that returns a reference to `UID`, dynamic fields can be read in other modules. +Because dynamic fields are attached to `UID`s, their usage in other modules depends on whether the +`UID` can be accessed. By default struct visibility protects the `id` field and won't let other +modules access it directly. However, if there's a public accessor method that returns a reference to +`UID`, dynamic fields can be read in other modules. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:exposed_uid}} ``` -In the example above, we show how to expose the `UID` of a `Character` object. This solution may work for some applications, however, it is important to remember that exposed `UID` allows reading _any_ dynamic field attached to the object. +In the example above, we show how to expose the `UID` of a `Character` object. This solution may +work for some applications, however, it is important to remember that exposed `UID` allows reading +_any_ dynamic field attached to the object. -If you need to expose the `UID` only within the package, use a restrictive visibility, like `public(package)`, or even better - use more specific accessor methods that would allow only reading specific fields. +If you need to expose the `UID` only within the package, use a restrictive visibility, like +`public(package)`, or even better - use more specific accessor methods that would allow only reading +specific fields. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-fields.move:exposed_uid_measures}} @@ -106,16 +159,25 @@ If you need to expose the `UID` only within the package, use a restrictive visib ## Dynamic Fields vs Fields -Dynamic Fields are more expensive than regular fields, as they require additional storage and costs for accessing them. Their flexibility comes at a price, and it is important to understand the implications when making a decision between using dynamic fields and regular fields. +Dynamic Fields are more expensive than regular fields, as they require additional storage and costs +for accessing them. Their flexibility comes at a price, and it is important to understand the +implications when making a decision between using dynamic fields and regular fields. ## Limits -Dynamic Fields are not subject to the [object size limit](./../guides/building-against-limits.md), and can be used to store large amounts of data. However, they are still subject to the [dynamic fields created limit](./../guides/building-against-limits.md), which is set to 1000 fields per transaction. +Dynamic Fields are not subject to the [object size limit](./../guides/building-against-limits.md), +and can be used to store large amounts of data. However, they are still subject to the +[dynamic fields created limit](./../guides/building-against-limits.md), which is set to 1000 fields +per transaction. ## Applications -Dynamic Fields can play a crucial role in applications of any complexity. They open up a variety of different use cases, from storing heterogeneous data to attaching objects as part of the application logic. They allow for certain [upgradeability practices](./../guides/upgradeability-practices.md) based on the ability to define them _later_ and change the type of the field. +Dynamic Fields can play a crucial role in applications of any complexity. They open up a variety of +different use cases, from storing heterogeneous data to attaching objects as part of the application +logic. They allow for certain [upgradeability practices](./../guides/upgradeability-practices.md) +based on the ability to define them _later_ and change the type of the field. ## Next Steps -In the next section we will cover [Dynamic Object Fields](./dynamic-object-fields.md) and explain how they differ from dynamic fields, and what are the implications of using them. +In the next section we will cover [Dynamic Object Fields](./dynamic-object-fields.md) and explain +how they differ from dynamic fields, and what are the implications of using them. diff --git a/book/src/programmability/dynamic-object-fields.md b/book/src/programmability/dynamic-object-fields.md index d1772f7e..4b58f454 100644 --- a/book/src/programmability/dynamic-object-fields.md +++ b/book/src/programmability/dynamic-object-fields.md @@ -1,14 +1,22 @@ # Dynamic Object Fields -> This section expands on the [Dynamic Fields](./dynamic-fields.md). Please, read it first to understand the basics of dynamic fields. +> This section expands on the [Dynamic Fields](./dynamic-fields.md). Please, read it first to +> understand the basics of dynamic fields. -Another variation of dynamic fields is _dynamic object fields_, which have certain differences from regular dynamic fields. In this section, we will cover the specifics of dynamic object fields and explain how they differ from regular dynamic fields. +Another variation of dynamic fields is _dynamic object fields_, which have certain differences from +regular dynamic fields. In this section, we will cover the specifics of dynamic object fields and +explain how they differ from regular dynamic fields. -> General recommendation is to avoid using dynamic object fields in favor of (just) dynamic fields, especially if there's no need for direct discovery through the ID. The extra costs of dynamic object fields may not be justified by the benefits they provide. +> General recommendation is to avoid using dynamic object fields in favor of (just) dynamic fields, +> especially if there's no need for direct discovery through the ID. The extra costs of dynamic +> object fields may not be justified by the benefits they provide. ## Definition -Dynamic Object Fields are defined in the `sui::dynamic_object_fields` module in the [Sui Framework](./sui-framework.md). They are similar to dynamic fields in many ways, but unlike them, dynamic object fields have an extra constraint on the `Value` type. The `Value` must have a combination of `key` and `store`, not just `store` as in the case of dynamic fields. +Dynamic Object Fields are defined in the `sui::dynamic_object_fields` module in the +[Sui Framework](./sui-framework.md). They are similar to dynamic fields in many ways, but unlike +them, dynamic object fields have an extra constraint on the `Value` type. The `Value` must have a +combination of `key` and `store`, not just `store` as in the case of dynamic fields. They're less explicit in their framework definition, as the concept itself is more abstract: @@ -23,9 +31,11 @@ public struct Wrapper has copy, drop, store { } ``` -Unlike `Field` type in the [Dynamic Fields](./dynamic-fields.md#definition) section, the `Wrapper` type only stores the name of the field. The value is the object itself, and is _not wrapped_. +Unlike `Field` type in the [Dynamic Fields](./dynamic-fields.md#definition) section, the `Wrapper` +type only stores the name of the field. The value is the object itself, and is _not wrapped_. -The constraints on the `Value` type become visible in the methods available for dynamic object fields. Here's the signature for the `add` function: +The constraints on the `Value` type become visible in the methods available for dynamic object +fields. Here's the signature for the `add` function: ```move /// Adds a dynamic object field to the object `object: &mut UID` at field @@ -39,7 +49,9 @@ public fun add( ) { /* implementation omitted */ } ``` -The rest of the methods which are identical to the ones in the [Dynamic Fields](./dynamic-fields.md#usage) section have the same constraints on the `Value` type. Let's list them for reference: +The rest of the methods which are identical to the ones in the +[Dynamic Fields](./dynamic-fields.md#usage) section have the same constraints on the `Value` type. +Let's list them for reference: - `add` - adds a dynamic object field to the object - `remove` - removes a dynamic object field from the object @@ -48,13 +60,19 @@ The rest of the methods which are identical to the ones in the [Dynamic Fields]( - `exists_` - checks if a dynamic object field exists - `exists_with_type` - checks if a dynamic object field exists with a specific type -Additionally, there is an `id` method which returns the `ID` of the `Value` object without specifying its type. +Additionally, there is an `id` method which returns the `ID` of the `Value` object without +specifying its type. ## Usage & Differences with Dynamic Fields -The main difference between dynamic fields and dynamic object fields is that the latter allows storing _only objects_ as values. This means that you can't store primitive types like `u64` or `bool`. It may be considered a limitation, if not for the fact that dynamic object fields are _not wrapped_ into a separate object. +The main difference between dynamic fields and dynamic object fields is that the latter allows +storing _only objects_ as values. This means that you can't store primitive types like `u64` or +`bool`. It may be considered a limitation, if not for the fact that dynamic object fields are _not +wrapped_ into a separate object. -> The relaxed requirement for wrapping keeps the object available for off-chain discovery via its ID. However, this property may not be outstanding if wrapped object indexing is implemented, making the dynamic object fields a redundant feature. +> The relaxed requirement for wrapping keeps the object available for off-chain discovery via its +> ID. However, this property may not be outstanding if wrapped object indexing is implemented, +> making the dynamic object fields a redundant feature. ```move {{#include ../../../packages/samples/sources/programmability/dynamic-object-fields.move:usage}} @@ -62,8 +80,14 @@ The main difference between dynamic fields and dynamic object fields is that the ## Pricing Differences -Dynamic Object Fields come a little more exensive than dynamic fields. Because of their internal structure, they require 2 objects: the Wrapper for Name and the Value. Because of this, the cost of adding and accessing object fields (loading 2 objects compared to 1 for dynamic fields) is higher. +Dynamic Object Fields come a little more exensive than dynamic fields. Because of their internal +structure, they require 2 objects: the Wrapper for Name and the Value. Because of this, the cost of +adding and accessing object fields (loading 2 objects compared to 1 for dynamic fields) is higher. ## Next Steps -Both dynamic field and dynamic object fields are powerful features which allow for innovative solutions in applications. However, they are relatively low-level and require careful handling to avoid orphaned fields. In the next section, we will introduce a higher-level abstraction - [Dynamic Collections](./dynamic-collections.md) - which can help with managing dynamic fields and objects more effectively. +Both dynamic field and dynamic object fields are powerful features which allow for innovative +solutions in applications. However, they are relatively low-level and require careful handling to +avoid orphaned fields. In the next section, we will introduce a higher-level abstraction - +[Dynamic Collections](./dynamic-collections.md) - which can help with managing dynamic fields and +objects more effectively. diff --git a/book/src/programmability/epoch-and-time.md b/book/src/programmability/epoch-and-time.md index 729f7bf8..62c907a6 100644 --- a/book/src/programmability/epoch-and-time.md +++ b/book/src/programmability/epoch-and-time.md @@ -1,10 +1,15 @@ # Epoch and Time -Sui has two ways of accessing the current time: `Epoch` and `Time`. The former represents operational periods in the system and changed roughly every 24 hours. The latter represents the current time in milliseconds since the Unix Epoch. Both can be accessed freely in the program. +Sui has two ways of accessing the current time: `Epoch` and `Time`. The former represents +operational periods in the system and changed roughly every 24 hours. The latter represents the +current time in milliseconds since the Unix Epoch. Both can be accessed freely in the program. ## Epoch -Epochs are used to separate the system into operational periods. During an epoch the validator set is fixed, however, at the epoch boundary, the validator set can be changed. Epochs play a crucial role in the consensus algorithm and are used to determine the current validator set. They are also used as measurement in the staking mechanism. +Epochs are used to separate the system into operational periods. During an epoch the validator set +is fixed, however, at the epoch boundary, the validator set can be changed. Epochs play a crucial +role in the consensus algorithm and are used to determine the current validator set. They are also +used as measurement in the staking mechanism. Epoch can be read from the [transaction context](./transaction-context.md): @@ -18,13 +23,20 @@ It is also possible to get the unix timestamp of the epoch start: {{#include ../../../packages/samples/sources/programmability/epoch-and-time.move:epoch_start}} ``` -Normally, epochs are used in staking and system operations, however, in custom scenarios they can be used to emulate 24h periods. They are critical if an application relies on the staking logic or needs to know the current validator set. +Normally, epochs are used in staking and system operations, however, in custom scenarios they can be +used to emulate 24h periods. They are critical if an application relies on the staking logic or +needs to know the current validator set. ## Time -For a more precise time measurement, Sui provides the `Clock` object. It is a system object that is updated during checkpoints by the system, which stores the current time in milliseconds since the Unix Epoch. The `Clock` object is defined in the `sui::clock` module and has a reserved address `0x6`. +For a more precise time measurement, Sui provides the `Clock` object. It is a system object that is +updated during checkpoints by the system, which stores the current time in milliseconds since the +Unix Epoch. The `Clock` object is defined in the `sui::clock` module and has a reserved address +`0x6`. -Clock is a shared object, but it a transaction attempting to access it mutably will fail. This limitation allows parallel access to the `Clock` object, which is important for maintaining performance. +Clock is a shared object, but it a transaction attempting to access it mutably will fail. This +limitation allows parallel access to the `Clock` object, which is important for maintaining +performance. ```move // File: sui-framework/clock.move @@ -46,7 +58,8 @@ struct Clock has key { } ``` -There is only one public function available in the `Clock` module - `timestamp_ms`. It returns the current time in milliseconds since the Unix Epoch. +There is only one public function available in the `Clock` module - `timestamp_ms`. It returns the +current time in milliseconds since the Unix Epoch. ```move {{#include ../../../packages/samples/sources/programmability/epoch-and-time.move:clock}} diff --git a/book/src/programmability/events.md b/book/src/programmability/events.md index 4496780d..5890e255 100644 --- a/book/src/programmability/events.md +++ b/book/src/programmability/events.md @@ -1,8 +1,12 @@ # Events -Events are a way to notify off-chain listeners about on-chain events. They are used to emit additional information about the transaction that is not stored - and, hence, can't be accessed - on-chain. Events are emitted by the `sui::event` module located in the [Sui Framework](./sui-framework.md). +Events are a way to notify off-chain listeners about on-chain events. They are used to emit +additional information about the transaction that is not stored - and, hence, can't be accessed - +on-chain. Events are emitted by the `sui::event` module located in the +[Sui Framework](./sui-framework.md). -> Any type with the [copy](./../move-basics/copy-ability.md) and [drop](./../move-basics/drop-ability.md) abilities can be emitted as an event. +> Any type with the [copy](./../move-basics/copy-ability.md) and +> [drop](./../move-basics/drop-ability.md) abilities can be emitted as an event. File: sui-framework/sources/event.move @@ -21,16 +25,23 @@ module sui::event { ## Emitting Events -Events are emitted using the `emit` function in the `sui::event` module. The function takes a single argument - the event to be emitted. The event data is passed by value, +Events are emitted using the `emit` function in the `sui::event` module. The function takes a single +argument - the event to be emitted. The event data is passed by value, ```move {{#include ../../../packages/samples/sources/programmability/events.move:emit}} ``` -The Sui Verifier requires the type passed to the `emit` function to be _internal to the module_. So emitting a type from another module will result in a compilation error. Primitive types, although they match the _copy_ and _drop_ requirement, are not allowed to be emitted as events. +The Sui Verifier requires the type passed to the `emit` function to be _internal to the module_. So +emitting a type from another module will result in a compilation error. Primitive types, although +they match the _copy_ and _drop_ requirement, are not allowed to be emitted as events. ## Event Structure -Events are a part of the transaction result and are stored in the _transaction effects_. As such, they natively have the `sender` field which is the address who sent the transaction. So adding a "sender" field to the event is not necessary. Similarly, event metadata contains the timestamp. But it is important to note that the timestamp is relative to the node and may vary a little from node to node. +Events are a part of the transaction result and are stored in the _transaction effects_. As such, +they natively have the `sender` field which is the address who sent the transaction. So adding a +"sender" field to the event is not necessary. Similarly, event metadata contains the timestamp. But +it is important to note that the timestamp is relative to the node and may vary a little from node +to node. diff --git a/book/src/programmability/fast-path.md b/book/src/programmability/fast-path.md index 4af52ddf..ca77b555 100644 --- a/book/src/programmability/fast-path.md +++ b/book/src/programmability/fast-path.md @@ -1,14 +1,27 @@ # Fast Path -Due to the object model and the data organization model of Sui, some operations can be performed in a more efficient and parallelized way. This is called the **fast path**. Transaction that touches shared state requires consensus because it can be accessed by multiple parties at the same time. However, if the transaction only touches the private state (owned objects), there is no need for consensus. This is the fast path. - -We have a favorite example for this: a coffee machine and a coffee cup. The coffee machine placed in the office is a shared resource - everyone can use it, but there can be only one user at a time. The coffee cup, on the other hand, is a private resource - it belongs to a specific person, and only that person can use it. To make coffee, one needs to use the coffee machine and wait if there's someone else using it. However, once the coffee is made and poured into the cup, the person can take the cup and drink the coffee without waiting for anyone else. - -The same principle applies to Sui. If a transaction only touches the private state (the cup with coffee), it can be executed without consensus. If it touches the shared state (the coffee machine), it requires consensus. This is the fast path. +Due to the object model and the data organization model of Sui, some operations can be performed in +a more efficient and parallelized way. This is called the **fast path**. Transaction that touches +shared state requires consensus because it can be accessed by multiple parties at the same time. +However, if the transaction only touches the private state (owned objects), there is no need for +consensus. This is the fast path. + +We have a favorite example for this: a coffee machine and a coffee cup. The coffee machine placed in +the office is a shared resource - everyone can use it, but there can be only one user at a time. The +coffee cup, on the other hand, is a private resource - it belongs to a specific person, and only +that person can use it. To make coffee, one needs to use the coffee machine and wait if there's +someone else using it. However, once the coffee is made and poured into the cup, the person can take +the cup and drink the coffee without waiting for anyone else. + +The same principle applies to Sui. If a transaction only touches the private state (the cup with +coffee), it can be executed without consensus. If it touches the shared state (the coffee machine), +it requires consensus. This is the fast path. ## Frozen objects -Consensus is only required for mutating the shared state. If the object is immutable, it is treated as a "constant" and can be accessed in parallel. Frozen objects can be used to share unchangeable data between multiple parties without requiring consensus. +Consensus is only required for mutating the shared state. If the object is immutable, it is treated +as a "constant" and can be accessed in parallel. Frozen objects can be used to share unchangeable +data between multiple parties without requiring consensus. ## In practice @@ -18,6 +31,9 @@ Consensus is only required for mutating the shared state. If the object is immut ## Special case: Clock -The `Clock` object with the reserved address `0x6` is a special case of a shared object which cannot be passed by a mutable reference in a regular transaction. An attempt to do so will not succeed, and the transaction will be rejected. Because of this limitation, the `Clock` object can only be accessed immutably, which allows executing transactions in parallel without consensus. +The `Clock` object with the reserved address `0x6` is a special case of a shared object which cannot +be passed by a mutable reference in a regular transaction. An attempt to do so will not succeed, and +the transaction will be rejected. Because of this limitation, the `Clock` object can only be +accessed immutably, which allows executing transactions in parallel without consensus. diff --git a/book/src/programmability/module-initializer.md b/book/src/programmability/module-initializer.md index a6d4a701..75ee0d17 100644 --- a/book/src/programmability/module-initializer.md +++ b/book/src/programmability/module-initializer.md @@ -1,9 +1,13 @@ # Module Initializer -A common use case in many applications is to run certain code just once when the package is published. Imagine a simple store module that needs to create the main Store object upon its publication. In Sui, this is achieved by defining an `init` function within the module. This function will automatically be called when the module is published. +A common use case in many applications is to run certain code just once when the package is +published. Imagine a simple store module that needs to create the main Store object upon its +publication. In Sui, this is achieved by defining an `init` function within the module. This +function will automatically be called when the module is published. - -> All of the modules' `init` functions are called during the publishing process. Currently, this behavior is limited to the publish command and does not extend to [package upgrades](./package-upgrades.md). +> All of the modules' `init` functions are called during the publishing process. Currently, this +> behavior is limited to the publish command and does not extend to +> [package upgrades](./package-upgrades.md). ```move {{#include ../../../packages/samples/sources/programmability/module-initializer.move:main}} @@ -20,14 +24,17 @@ In the same package, another module can have its own `init` function, encapsulat The function is called on publish, if it is present in the module and follows the rules: - The function has to be named `init`, be private and have no return values. -- Takes one or two arguments: [One Time Witness](./one-time-witness.md) (optional) and [TxContext](./transaction-context.md). With `TxContext always being the last argument. +- Takes one or two arguments: [One Time Witness](./one-time-witness.md) (optional) and + [TxContext](./transaction-context.md). With `TxContext always being the last argument. ```move fun init(ctx: &mut TxContext) { /* ... */} fun init(otw: OTW, ctx: &mut TxContext) { /* ... */ } ``` -TxContext can also be passed as immutable reference: `&TxContext`. However, practically speaking, it should always be `&mut TxContext` since the `init` function can't access the onchain state and to create new objects it requires the mutable reference to the context. +TxContext can also be passed as immutable reference: `&TxContext`. However, practically speaking, it +should always be `&mut TxContext` since the `init` function can't access the onchain state and to +create new objects it requires the mutable reference to the context. ```move fun init(ctx: &TxContext) { /* ... */} @@ -36,12 +43,22 @@ fun init(otw: OTW, ctx: &TxContext) { /* ... */ } ## Trust and security -While `init` function can be used to create sensitive objects once, it is important to know that the same object (eg. `StoreOwnerCap` from the first example) can still be created in another function. Especially given that new functions can be added to the module during an upgrade. So the `init` function is a good place to set up the initial state of the module, but it is not a security measure on its own. +While `init` function can be used to create sensitive objects once, it is important to know that the +same object (eg. `StoreOwnerCap` from the first example) can still be created in another function. +Especially given that new functions can be added to the module during an upgrade. So the `init` +function is a good place to set up the initial state of the module, but it is not a security measure +on its own. -There are ways to guarantee that the object was created only once, such as the [One Time Witness](./one-time-witness.md). And there are ways to limit or disable the upgrade of the module, which we will cover in the [Package Upgrades](./package-upgrades.md) chapter. +There are ways to guarantee that the object was created only once, such as the +[One Time Witness](./one-time-witness.md). And there are ways to limit or disable the upgrade of the +module, which we will cover in the [Package Upgrades](./package-upgrades.md) chapter. ## Next steps -As follows from the definition, the `init` function is guaranteed to be called only once when the module is published. So it is a good place to put the code that initializes module's objects and sets up the environment and configuration. +As follows from the definition, the `init` function is guaranteed to be called only once when the +module is published. So it is a good place to put the code that initializes module's objects and +sets up the environment and configuration. -For example, if there's a [Capability](./capability.md) which is required for certain actions, it should be created in the `init` function. In the next chapter we will talk about the `Capability` pattern in more detail. +For example, if there's a [Capability](./capability.md) which is required for certain actions, it +should be created in the `init` function. In the next chapter we will talk about the `Capability` +pattern in more detail. diff --git a/book/src/programmability/one-time-witness.md b/book/src/programmability/one-time-witness.md index 33cccbbd..d63c8ef8 100644 --- a/book/src/programmability/one-time-witness.md +++ b/book/src/programmability/one-time-witness.md @@ -1,6 +1,8 @@ # One Time Witness -While regular [Witness](./witness-pattern.md) is a great way to statically prove the ownership of a type, there are cases, where we need to ensure that a witness is used only once. And this is the purpose of the One Time Witness (OTW). +While regular [Witness](./witness-pattern.md) is a great way to statically prove the ownership of a +type, there are cases, where we need to ensure that a witness is used only once. And this is the +purpose of the One Time Witness (OTW). diff --git a/book/src/storage/key-ability.md b/book/src/storage/key-ability.md index 8bd2dd07..75bf8c9e 100644 --- a/book/src/storage/key-ability.md +++ b/book/src/storage/key-ability.md @@ -1,14 +1,22 @@ # The Key Ability -In the [Basic Syntax](./../move-basics) chapter we already covered two out of four abilities - [Drop](./drop-ability.md) and [Copy](./copy-ability.md). 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. +In the [Basic Syntax](./../move-basics) chapter we already covered two out of four abilities - +[Drop](./drop-ability.md) and [Copy](./copy-ability.md). 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](./../object), the `key` ability naturally became the defining ability for the object. +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](./../object), 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`. +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 { @@ -25,9 +33,12 @@ public fun new(name: String, ctx: &mut TxContext): Object { } ``` -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. +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. +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.