Migrate to Move 2024
Move 2024 offers new features, including method syntax, positional fields, and loop labels.
Migrating to the Move 2024 edition introduces changes that make Move easier to write, and hopefully easier to read. The relatively few breaking changes in the source language better position Move to handle future advancements.
Many of these changes enhance the source language, affecting the compiler without requiring any changes to the binary representation published on chain.
Existing code will continue to compile, even with the addition of these new features. And because these features are opt-in, you can write your packages with the new features, even if your dependencies do not include them. Opting to take advantage of the new features in your current modules, however, introduces a few breaking changes.
Read our migration guide on GitHub for full details.
How to migrate
To migrate a project to Move 2024 Beta, you have two options:
- Delete your existing
Move.lock
file (if one exists) to make sure you're using the newestsui-framework
version. - Run
sui move migrate
in the root of your Move project. See the Automatic migration section of the migration guide for more information.- Alternatively, update your
Move.toml
file's[package]
entry to includeedition = "2024.beta"
. If you do this, you might receive a number of new errors as part of our breaking changes.
- Alternatively, update your
Automatic migration
Move 2024 includes an automatic migration script that you can use by calling sui move migrate
in the root of your Move project. Upon running, your console prompts you for which Move edition to use. If you select 2024.beta
, the script invokes the compiler and attempts to automatically update your code to avoid the breaking changes the update introduces (including marking structs as public
, mutable variables with the mut
keyword, avoiding restricted keywords, swapping friends
for public(package)
, and even updating paths to global paths in many cases).
After this script runs, your console displays a diff of the changes the script intends to make. If you accept the changes, the script updates your code and your Move.toml
file automatically. You are now using Move 2024 Beta.
New features
Here is a brief overview of some of the new features in Move 2024.
Method syntax
You can call certain functions now as methods using the .
syntax. For example, the following call:
vector::push_back(&mut v, coin::value(&c));
can now be written as:
v.push_back(c.value());
Where the receiver of the method (v
and c
in this example) is automatically borrowed if necessary (as &mut v
and &c
respectively).
You can call any function defined in the same module as the receiver's type as a method if it takes the receiver as its first argument.
For functions defined outside the module, you can declare methods using public use fun
and use fun
.
Index syntax
With method syntax, you can annotate certain functions as being #[syntax(index)]
methods. You then call these methods using v[i]
-style calls.
For example,
*&mut v[i] = v[j];
resolves to
*vector::borrow_mut(&mut v, i) = *vector::borrow(&v, j);
public(package)
friend
declarations, and the associated public(friend)
visibility modifiers, are deprecated. In their place is the public(package)
visibility modifier, which allows calling functions only within the same package where they are defined.
Positional fields
You can now define structs with positional fields, which are accessed by a zero-based index. For example,
public struct Pair(u64, u64) has copy, drop, store;
then to access each field,
public fun sum(p: &Pair): u64 {
p.0 + p.1
}
And as this example shows, you can now declare abilities after the struct field list.
Nested use and standard library defaults
You can now nest use
aliases for more conciseness.
use sui::{balance, coin::{Self, Coin}};
Additionally, the following use declarations are now automatically included in every module:
use std::vector;
use std::option::{Self, Option};
use sui::object::{Self, ID, UID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
Automatic referencing in equality
Equality operations, ==
and !=
, now automatically borrow if one side is a reference and the other is not. For example,
fun check(x: u64, r: &u64): bool {
x == r
}
is equivalent to
fun check(x: u64, r: &u64): bool {
&x == r
}
This automatic borrowing can occur on either side of ==
and !=
.
Loop labels
When nesting loops, it can be convenient to break to the outer loop. For example,
let mut i = 0;
let mut j = 0;
let mut terminate_loop = false;
while (i < 10) {
while (j < 10) {
if (haystack(i, j) == needle) {
terminate_loop = true;
break;
};
j = j + 1;
};
if (terminate_loop) break;
i = i + 1;
}
Now, you can directly name the outer loop (outer
in this case) and break it all at once:
let mut i = 0;
let mut j = 0;
'outer: while (i < 10) {
while (j < 10) {
if (haystack(i, j) == needle) break'outer;
j = j + 1;
};
i = i + 1;
}
break
with value
It's now possible to break with a value from a loop. For example,
let mut i = 0;
let x: u64 = loop {
if (v[i] > 10) break i;
i = i + 1;
};
You can achieve this with labels, as well. For example,
let mut i = 0;
let mut j = 0;
let item = 'outer: loop {
while (j < 10) {
let item = haystack(i, j);
if (item == needle) break'outer option::some(item);
j = j + 1;
};
i = i + 1;
if (i == 10) break option::none();
};
Breaking changes
Breaking changes are, unfortunately, a growing pain in Move 2024. We anticipate these changes to be minimally invasive and provided a migration script to automate them in most cases. In addition, these changes pave the way for new features still to come in Move 2024.
Datatype visibility requirements
Currently, all structs in Move are, by convention, public: any other module or package can import them and refer to them by type. To make this clearer, Move 2024 requires that all structs be declared with the public keyword. For example,
// legacy code
struct S { x: u64 }
// Move 2024 code
public struct S { x: u64 }
Any non-public struct produces an error at this time, although the Move team is working on new visibility options for future releases.
Mutability requirements
Previously, all variables in Move were implicitly mutable. For example,
fun f(s: S, y: u64): u64 {
let a = 0;
let S { x } = s;
a = 1;
x = 10;
y = 5;
x + y
}
Now, you must declare mutable variables explicitly:
fun f(s: S, mut y: u64): u64 {
let mut a = 0;
let S { mut x } = 5;
a = 1;
x = 10;
y = 5;
x + y
}
The compiler now produces an error if you attempt to reassign or borrow a variable mutably without this explicit declaration.
Removing friends and public(friend)
Friends and the public(friend)
visibilities were introduced early in Move's development, predating even the package system. As indicated in the public(package) section, public(package)
deprecates public(friend)
in Move 2024.
The following declaration now produces an error:
module pkg::m {
friend pkg::a;
public(friend) fun f() { ... }
}
module pkg::a {
fun calls_f() { ... pkg::m::f() ... }
}
Instead, if you want your function to be visible only in the package, write:
module pkg::m {
public(package) fun f() { ... }
}
module pkg::a {
// this now works directly
fun calls_f() { ... pkg::m::f() ... }
}
New keywords
Looking toward the future, Move 2024 Beta adds the following keywords to the language: enum
, for
, match
, mut
, and type
. The compiler, unfortunately, now produces parsing errors when it finds these in other positions. This is a necessary change as the language matures. If you perform automatic migration, the migration tool renames these as enum
and so on, rewriting the code to use these escaped forms.
Revised paths and namespaces
Move 2024 revises how paths and namespaces work compared to legacy Move, toward easing enum
aliasing in the future. Consider the following snippet from a test annotation in the sui_system
library:
use sui_system::sui_system;
...
#[expected_failure(abort_code = sui_system::validator_set::EInvalidCap)]
Legacy Move would always treat a three-part name as an address (sui_system
), module (validator_set
), and module member (EInvalidCap
). Move 2024 respects scope for use
, so sui_system
in the attribute resolves to the module, producing a name resolution error overall.
To avoid cases where this is the intended behavior, Move 2024 introduces a prefix operation for global qualification. To use it, you can rewrite this annotation as:
use sui_system::sui_system;
...
#[expected_failure(abort_code = ::sui_system::validator_set::EInvalidCap)]
// ^ note `::` here
The migration script attempts to remediate naming errors using global qualification when possible.
Follow along
The beta release of Move 2024 comes with some powerful new features beyond the breaking changes described here. There are also more on the horizon. Join the Sui newsletter to learn about new, exciting features coming to Move this year, including syntactic macros, enums with pattern matching, and other user-defined syntax extensions.
Please, provide any feedback or report any issues you encounter via GitHub, Discord, or the Sui Developer Forums.