---
tags: research
---
# Move Language Overview
Concise document outlining Move Language features.
## Types
Integer: `u8`, `u64`, `u128` (cast with `as`)
Boolean: `bool`
Address: `address`
Comments: `// ...`, `/* */`
## Expressions
Empty: `()`
Literal: `10;`
Assignment: `let name = literal;`
Operators: `+`, `-`, `*`, `/`, `%`, `<<`, `>>`, `&`, `^`, `|`
Use underscore for unused vars: `_ = literal`. Else compiler error.
Shadowing without using the first assigned value will throw.
```
script {
fun main() {
let a = 1; // unused
let a = 2;
let _ = a;
}
}
```
Block Expression: `{}`
Blocks return values if the final line does not end with `;`.
```
let a = {
let b = 1;
b + 1
};
// a == 2
```
## Control Flow
If/else: `if {} else {}`. End w/ semi colon if block returns.
While: `while (bool_expression) {};`
Infinite Loop: `loop {};`
Compiler doesn't check for halting problem.
Continue / Break:
```
script {
fun main() {
let a = 1;
loop {
a = a + 1;
if (a / 2 == 0) continue;
if (a == 5) break;
// ...
}
}
}
```
Weird Rule: `if (bool_exp) continue;` works but not `if (bool_exp) { continue; }`
Above applies for `break` as well.
Abort: `if (bool_exp) { abort err_code; }`
Assert: `assert!(bool_exp, err_code)`
## Module and Import
Standard Library: `0x1`
Define module: `module ModName {}`
Direct import: `0x1::Offer::create(bool_exp, code);`
Use Keyword: `use 0x1::Vector as Vec;`
Method access: `Module::Method()`
Member import: `use Module::Struct::member;`
Multi-member import: `use Module::Struct::{member0, member1};`
Self import:
```
script {
// Vector::Self == Vector
use 0x1::Vector::{
Self,
empty
};
fun main() {
let vec = empty<u8>();
Vector::push_back(&mut vec, 10);
}
}
```
## Constants
Define: `const NAME: type = literal;`
Must define constant in module.
## Functions
Definition: `fun name(arg0: type0, .., arg_n: type_n): ret_type {}`
Script can only contain `main` function. Executed as transaction.
Multi Return: `fun mr(a: u8, b, u8): (c: u8, d: u8) {}`
Module function visibility is private by default, make public with `public fun...`
Native functions: Defined by the VM itself and may vary in different move impls.
```
module Signer {
native public fun borrow_address(s: &signer): &address;
}
```
## Structures
Struct: `struct Name { field: type, field: type }`
Structs can have other structs as types.
No recursive structs: `struct Node { child: Node } // NO`
Create instance: `let country = Country { id: 0, population: 1 };`
Access struct field: `country.id`
Destructure: `let (id, population): (u8, u8) = country;`
Also destructure: `let Country { id, population } = country;`
```
module Country {
struct Country {
id: u8,
population: u8
}
public fun new_country(id: u8, population: u8): Country {
Country {
id,
population
}
}
public fun id(country: Country): u8 {
country.id
}
public fun population(country: Country): u8 {
country.population
}
// ...
}
script {
use {{sender}}::Country as C;
use 0x1::Debug;
fun main() {
let country = C::new_country(1, 100);
Debug::print<u8>(&C::id(&country));
Debug::print<u8>(&C::id(&country));
C::destroy(country);
}
}
```
## Types and Abilities
Four abilities:
1. Copy: can be cloned/copied
2. Drop: can be dropped by end of scope
3. Key: can be used as key for global storage ops
4. Store: can be stored in global storage
Ability declaration: `struct Name as copy, drop, key, store {}`
## Ownership and References
It's like rust.
Variable has a single owner.
When variable is passed to a function, the function now owns it. It cannot be
used after this UNLESS the function returns ownership.
Cloning will create a copy and pass ownership of the copy to the function.
Primitive types implicitly copy.
References are either immutable `&value` or mutable `&mut value`.
Borrow checking happens at compile time.
Dereferencing happens with `*ref_of_value`. Creates a copy.
Copy inner field of struct:
```
module M {
struct H as copy {}
struct T { inner: H }
public fun copy_inner(t: &T): H {
*&t.inner
}
}
```
## Generics
Stand-in type. Replaced at compile time as necessary.
```
module Storage {
struct Box<T> {
value: T,
}
public fun create_box_u64(value: u64): Box<u64> {
Box<u64>{ value }
}
// this constrains the `T` type to have `copy`.
public fun create_box_with_copy<T: copy>(value: T): Box<T: copy> {
Box<T: copy>{ value }
}
}
```
Multi type generic: `struct Name<T0, T1> { a: T0, b: t1 }`
## Vectors
Bring into scope: `use 0x1::Vector;`
Methods:
create empty: `Vector::empty<E>(): vector<E>;`
get length: `Vector::length<E>(v: &vector<E>): u64;`
push element: `Vector::push_back<E>(v: &mut vector<E>, e: E);`
pop element and return: `Vector::pop_back<E>(v: &mut vector<E>): E;`
borrow immutable: `Vector::borrow<E>(v: &vector<E>, i: u64): &E;`
borrow mutable: `Vector::borrow_mut<E>(v: &mut vector<E>, i: u64): &E; // may be typo`
Use bytes as vector: `let str: vector<u8> = x"12435";`
## Programmable Resources
Resources are custom types to encode digital assets with programability (jfc such marketing)
They are ordinary values in the lang. Can be stored as data structs, args, rets, etc.
Resources cannot be duped, reused, or discarded. Statically enforced by the Move VM
verifier.
## Sender as Signer
Signer is non-copyable resource-like type that holds tx sender address.
Only has `drop`.
Canonical name of var holding signer is `account`.
Signer mod: `0x1::Signer::{borrow_address, address_of};`
In modules, `&signer`as arg indicates the sender address.
## Resource
Definition (only key and store): `struct T has key, store { field: u8 }`
Key allows struct to be storage identifier.
Store allows struct to be stored under key.
Resource properties:
1. stored under account, exists only when assigned to account
2. account can only hold one resource of one type
3. resource cannot be copied nor dropped, only stored
4. resource value must be used. when read, must be stored or destructured
## Create and Move Resource
```
// modules/Collection.move
module Collection {
use 0x1::Vector;
struct Item has drop, store {
// todo
}
struct Collection has store, key {
items: vector<Item>
}
public fun start_collection(account: &signer) {
// native fun move_to<T: key>(account: &signer, value: T);
move_to<Collection>(amount, Collection { items: Vector::empty<Collection>() })
}
public fun exists_at(at: address): bool {
// native fun exists_at<T: key>(addr: address): bool;
exists<Collection>(at)
}
}
```
## Read and Modify Resource
```
module Collection {
use 0x1::Signer;
use 0x1::Vector;
struct Item has store, drop {}
struct Collection has key, store {
items: vector<Item>
}
public fun size(account: &signer): u64 aquires Collection {
let owner = Signer::address_of(account);
let collection = borrow_global<Collection>(owner);
Vector::length(&collection.items)
}
public fun add_item(account: &signer) aquires T {
// native fun borrow_global_mut<T: key>(addr: address): &mut T;
let collection = borrow_global_mut<T>(Signer::address_of(account));
Vector::push_back(&mut collection.items, Item {});
}
```
Aquires keyword put after func ret value, explicitly defines resources aquired by it.
## Take and Destroy Resouce
```
module Collection {
public fun destroy(account: &signer) aquires Collection {
// native fun move_from<T: key>(addr: address): T;
let collection = move_from<Collection>(Signer::address_of(account));
// MUST use. So we use `_` to "use" it.
let Collection { items: _ } = collections;
// resource destroyed.
}
```
## Friends
Used to declare modules that are trusted by the current module.
Trusted can call any function defined with `public(friend)` visibility.
Declare friend mod: `friend Address::Name`, `friend mod_alias`
Rules:
- Mod cannot declare itself as friend
- Friend mods must be known by the compiler
- Friend mods must be within same account address
- Friend relationships cannot create cyclic mod dependencies
- Mod friend list cannot have duplicates
## Packages
```
a_move_package
├── Move.toml (required)
├── sources (required)
├── examples (optional, test & dev mode)
├── scripts (optional)
├── doc_templates (optional)
└── tests (optional, test mode)
```
`Move.toml`:
```
[package]
name = <string>
version = "<uint>.<uint>.<uint>"
license* = <string>
authors* = [<string>]
[addresses]
<addr_name> = "_" | "<hex_address>"
[dependencies]
<string> = { local = <string>, addr_subst* = { (<string> = (<string> | "<hex_addr>"))+ }}
<string> = { git = "<git_url>", subdir=<dir_path>, rev = <commit>, addr_subst* = ... }
[dev-addresses]
<addr_name> = "_" | "<hex_addr>"
[dev-dependencies]
...
```
## Unit Tests
Three annotations:
- `#[test]`
- `#[test_only]`
- `#[expected_failure]`
The `#[test]` and `#[test_only]` can be used with or without args.
Use Args:
```
#[test(arg = @0xC0FFEE)]
fun t_sig(arg: signer) {}
```