Resources

Resources are types that can only exist in one location at a time and must be used exactly once.

Resources must be created (instantiated) by using the create keyword.

At the end of a function which has resources (variables, constants, parameters) in scope, the resources must be either moved or destroyed.

They are moved when used as an initial value for a constant or variable, when assigned to a different variable, when passed as an argument to a function, and when returned from a function.

Resources can be explicitly destroyed using the destroy keyword.

Accessing a field or calling a function of a resource does not move or destroy it.

When the resource is moved, the constant or variable that referred to the resource before the move becomes invalid. An invalid resource cannot be used again.

To make the usage and behaviour of resource types explicit, the prefix @ must be used in type annotations of variable or constant declarations, parameters, and return types.

To make moves of resources explicit, the move operator <- must be used when the resource is the initial value of a constant or variable, when it is moved to a different variable, when it is moved to a function as an argument, and when it is returned from a function.

// Declare a resource named `SomeResource`, with a variable integer field.
//
pub resource SomeResource {
    pub var value: Int

    init(value: Int) {
        self.value = value
    }
}

// Declare a constant with value of resource type `SomeResource`.
//
let a: @SomeResource <- create SomeResource(value: 0)

// *Move* the resource value to a new constant.
//
let b <- a

// Invalid: Cannot use constant `a` anymore as the resource that it referred to
// was moved to constant `b`.
//
a.value

// Constant `b` owns the resource.
//
b.value // equals 0

// Declare a function which accepts a resource.
//
// The parameter has a resource type, so the type annotation must be prefixed with `@`.
//
pub fun use(resource: @SomeResource) {
    // ...
}

// Call function `use` and move the resource into it.
//
use(resource: <-b)

// Invalid: Cannot use constant `b` anymore as the resource
// it referred to was moved into function `use`.
//
b.value

A resource object cannot go out of scope and be dynamically lost. The program must either explicitly destroy it or move it to another context.

{
    // Declare another, unrelated value of resource type `SomeResource`.
    //
    let c <- create SomeResource(value: 10)

    // Invalid: `c` is not used before the end of the scope, but must be.
    // It cannot be lost.
}
// Declare another, unrelated value of resource type `SomeResource`.
//
let d <- create SomeResource(value: 20)

// Destroy the resource referred to by constant `d`.
//
destroy d

// Invalid: Cannot use constant `d` anymore as the resource
// it referred to was destroyed.
//
d.value

To make it explicit that the type is a resource type and must follow the rules associated with resources, it must be prefixed with @ in all type annotations, e.g. for variable declarations, parameters, or return types.

// Declare a constant with an explicit type annotation.
//
// The constant has a resource type, so the type annotation must be prefixed with `@`.
//
let someResource: @SomeResource <- create SomeResource(value: 5)

// Declare a function which consumes a resource and destroys it.
//
// The parameter has a resource type, so the type annotation must be prefixed with `@`.
//
pub fun use(resource: @SomeResource) {
    destroy resource
}

// Declare a function which returns a resource.
//
// The return type is a resource type, so the type annotation must be prefixed with `@`.
// The return statement must also use the `<-` operator to make it explicit the resource is moved.
//
pub fun get(): @SomeResource {
    let newResource <- create SomeResource()
    return <-newResource
}

Resources must be used exactly once.

// Declare a function which consumes a resource but does not use it.
// This function is invalid, because it would cause a loss of the resource.
//
pub fun forgetToUse(resource: @SomeResource) {
    // Invalid: The resource parameter `resource` is not used, but must be.
}
// Declare a constant named `res` which has the resource type `SomeResource`.
let res <- create SomeResource()

// Call the function `use` and move the resource `res` into it.
use(resource: <-res)

// Invalid: The resource constant `res` cannot be used again,
// as it was moved in the previous function call.
//
use(resource: <-res)

// Invalid: The resource constant `res` cannot be used again,
// as it was moved in the previous function call.
//
res.value
// Declare a function which has a resource parameter but does not use it.
// This function is invalid, because it would cause a loss of the resource.
//
pub fun forgetToUse(resource: @SomeResource) {
    // Invalid: The resource parameter `resource` is not used, but must be.
}
// Declare a function which has a resource parameter.
// This function is invalid, because it does not always use the resource parameter,
// which would cause a loss of the resource.
//
pub fun sometimesDestroy(resource: @SomeResource, destroy: Bool) {
    if destroyResource {
        destroy resource
    }
    // Invalid: The resource parameter `resource` is not always used, but must be.
    // The destroy statement is not always executed, so at the end of this function
    // it might have been destroyed or not.
}
// Declare a function which has a resource parameter.
// This function is valid, as it always uses the resource parameter,
// and does not cause a loss of the resource.
//
pub fun alwaysUse(resource: @SomeResource, destroyResource: Bool) {
    if destroyResource {
        destroy resource
    } else {
        use(resource: <-resource)
    }
    // At the end of the function the resource parameter was definitely used:
    // It was either destroyed or moved in the call of function `use`.
}
// Declare a function which has a resource parameter.
// This function is invalid, because it does not always use the resource parameter,
// which would cause a loss of the resource.
//
pub fun returnBeforeDestroy(: Bool) {
    let res <- create SomeResource(value: 1)
    if move {
        use(resource: <-res)
        return
    } else {
        // Invalid: When this function returns here, the resource variable
        // `res` was not used, but must be.
        return
    }
    // Invalid: the resource variable `res` was potentially moved in the
    // previous if-statement, and both branches definitely return,
    // so this statement is unreachable.
    destroy res
}

Last updated