Skip to main content
Version: Next

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.

The Move Operator (<-)

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.


_43
// Declare a resource named `SomeResource`, with a variable integer field.
_43
//
_43
access(all) resource SomeResource {
_43
access(all) var value: Int
_43
_43
init(value: Int) {
_43
self.value = value
_43
}
_43
}
_43
_43
// Declare a constant with value of resource type `SomeResource`.
_43
//
_43
let a: @SomeResource <- create SomeResource(value: 0)
_43
_43
// *Move* the resource value to a new constant.
_43
//
_43
let b <- a
_43
_43
// Invalid: Cannot use constant `a` anymore as the resource that it referred to
_43
// was moved to constant `b`.
_43
//
_43
a.value
_43
_43
// Constant `b` owns the resource.
_43
//
_43
b.value // equals 0
_43
_43
// Declare a function which accepts a resource.
_43
//
_43
// The parameter has a resource type, so the type annotation must be prefixed with `@`.
_43
//
_43
access(all) fun use(resource: @SomeResource) {
_43
// ...
_43
}
_43
_43
// Call function `use` and move the resource into it.
_43
//
_43
use(resource: <-b)
_43
_43
// Invalid: Cannot use constant `b` anymore as the resource
_43
// it referred to was moved into function `use`.
_43
//
_43
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.


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


_12
// Declare another, unrelated value of resource type `SomeResource`.
_12
//
_12
let d <- create SomeResource(value: 20)
_12
_12
// Destroy the resource referred to by constant `d`.
_12
//
_12
destroy d
_12
_12
// Invalid: Cannot use constant `d` anymore as the resource
_12
// it referred to was destroyed.
_12
//
_12
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.


_23
// Declare a constant with an explicit type annotation.
_23
//
_23
// The constant has a resource type, so the type annotation must be prefixed with `@`.
_23
//
_23
let someResource: @SomeResource <- create SomeResource(value: 5)
_23
_23
// Declare a function which consumes a resource and destroys it.
_23
//
_23
// The parameter has a resource type, so the type annotation must be prefixed with `@`.
_23
//
_23
access(all) fun use(resource: @SomeResource) {
_23
destroy resource
_23
}
_23
_23
// Declare a function which returns a resource.
_23
//
_23
// The return type is a resource type, so the type annotation must be prefixed with `@`.
_23
// The return statement must also use the `<-` operator to make it explicit the resource is moved.
_23
//
_23
access(all) fun get(): @SomeResource {
_23
let newResource <- create SomeResource()
_23
return <-newResource
_23
}

Resources must be used exactly once.


_10
// Declare a function which consumes a resource but does not use it.
_10
// This function is invalid, because it would cause a loss of the resource.
_10
//
_10
access(all) fun forgetToUse(resource: @SomeResource) {
_10
// Invalid: The resource parameter `resource` is not used, but must be.
_10
}


_15
// Declare a constant named `res` which has the resource type `SomeResource`.
_15
let res <- create SomeResource()
_15
_15
// Call the function `use` and move the resource `res` into it.
_15
use(resource: <-res)
_15
_15
// Invalid: The resource constant `res` cannot be used again,
_15
// as it was moved in the previous function call.
_15
//
_15
use(resource: <-res)
_15
_15
// Invalid: The resource constant `res` cannot be used again,
_15
// as it was moved in the previous function call.
_15
//
_15
res.value


_12
// Declare a function which has a resource parameter.
_12
// This function is invalid, because it does not always use the resource parameter,
_12
// which would cause a loss of the resource.
_12
//
_12
access(all) fun sometimesDestroy(resource: @SomeResource, destroyResource: Bool) {
_12
if destroyResource {
_12
destroy resource
_12
}
_12
// Invalid: The resource parameter `resource` is not always used, but must be.
_12
// The destroy statement is not always executed, so at the end of this function
_12
// it might have been destroyed or not.
_12
}


_13
// Declare a function which has a resource parameter.
_13
// This function is valid, as it always uses the resource parameter,
_13
// and does not cause a loss of the resource.
_13
//
_13
access(all) fun alwaysUse(resource: @SomeResource, destroyResource: Bool) {
_13
if destroyResource {
_13
destroy resource
_13
} else {
_13
use(resource: <-resource)
_13
}
_13
// At the end of the function the resource parameter was definitely used:
_13
// It was either destroyed or moved in the call of function `use`.
_13
}


_19
// Declare a function which has a resource parameter.
_19
// This function is invalid, because it does not always use the resource parameter,
_19
// which would cause a loss of the resource.
_19
//
_19
access(all) fun returnBeforeDestroy(move: Bool) {
_19
let res <- create SomeResource(value: 1)
_19
if move {
_19
use(resource: <-res)
_19
return
_19
} else {
_19
// Invalid: When this function returns here, the resource variable
_19
// `res` was not used, but must be.
_19
return
_19
}
_19
// Invalid: the resource variable `res` was potentially moved in the
_19
// previous if-statement, and both branches definitely return,
_19
// so this statement is unreachable.
_19
destroy res
_19
}

Resource Variables

Resource variables cannot be assigned to, as that would lead to the loss of the variable's current resource value.

Instead, use a swap statement (<->) or shift statement (<- target <-) to replace the resource variable with another resource.


_23
access(all) resource R {}
_23
_23
var x <- create R()
_23
var y <- create R()
_23
_23
// Invalid: Cannot assign to resource variable `x`,
_23
// as its current resource would be lost
_23
//
_23
x <- y
_23
_23
// Instead, use a swap statement.
_23
//
_23
var replacement <- create R()
_23
x <-> replacement
_23
// `x` is the new resource.
_23
// `replacement` is the old resource.
_23
_23
// Or use the shift statement (`<- target <-`)
_23
// This statement moves the resource out of `x` and into `oldX`,
_23
// and at the same time assigns `x` with the new value on the right-hand side.
_23
let oldX <- x <- create R()
_23
// oldX still needs to be explicitly handled after this statement
_23
destroy oldX

Resource Destructors

Resource may have a destructor, which is executed when the resource is destroyed. Destructors have no parameters and no return value and are declared using the destroy name. A resource may have only one destructor.


_15
var destructorCalled = false
_15
_15
access(all) resource Resource {
_15
_15
// Declare a destructor for the resource, which is executed
_15
// when the resource is destroyed.
_15
//
_15
destroy() {
_15
destructorCalled = true
_15
}
_15
}
_15
_15
let res <- create Resource()
_15
destroy res
_15
// `destructorCalled` is `true`

Nested Resources

Fields in composite types behave differently when they have a resource type.

If a resource type has fields that have a resource type, it must declare a destructor, which must invalidate all resource fields, i.e. move or destroy them.


_28
access(all) resource Child {
_28
let name: String
_28
_28
init(name: String)
_28
self.name = name
_28
}
_28
}
_28
_28
// Declare a resource with a resource field named `child`.
_28
// The resource *must* declare a destructor
_28
// and the destructor *must* invalidate the resource field.
_28
//
_28
access(all) resource Parent {
_28
let name: String
_28
var child: @Child
_28
_28
init(name: String, child: @Child) {
_28
self.name = name
_28
self.child <- child
_28
}
_28
_28
// Declare a destructor which invalidates the resource field
_28
// `child` by destroying it.
_28
//
_28
destroy() {
_28
destroy self.child
_28
}
_28
}

Accessing a field or calling function on a resource field is valid, however moving a resource out of a variable resource field is not allowed. Instead, use a swap statement to replace the resource with another resource.


_15
let child <- create Child(name: "Child 1")
_15
let parent <- create Parent(name: "Parent", child: <-child)
_15
_15
child.name // is "Child 1"
_15
parent.child.name // is "Child 1"
_15
_15
// Invalid: Cannot move resource out of variable resource field.
_15
let childAgain <- parent.child
_15
_15
// Instead, use a swap statement.
_15
//
_15
var otherChild <- create Child(name: "Child 2")
_15
parent.child <-> otherChild
_15
// `parent.child` is the second child, Child 2.
_15
// `otherChild` is the first child, Child 1.

Resources in Closures

Resources can not be captured in closures, as that could potentially result in duplications.


_13
resource R {}
_13
_13
// Invalid: Declare a function which returns a closure which refers to
_13
// the resource parameter `resource`. Each call to the returned function
_13
// would return the resource, which should not be possible.
_13
//
_13
fun makeCloner(resource: @R): fun(): @R {
_13
return fun (): @R {
_13
return <-resource
_13
}
_13
}
_13
_13
let test = makeCloner(resource: <-create R())

Resources in Arrays and Dictionaries

Arrays and dictionaries behave differently when they contain resources: It is not allowed to index into an array to read an element at a certain index or assign to it, or index into a dictionary to read a value for a certain key or set a value for the key.

Instead, use a swap statement (<->) or shift statement (<- target <-) to replace the accessed resource with another resource.


_34
resource R {}
_34
_34
// Declare a constant for an array of resources.
_34
// Create two resources and move them into the array.
_34
// `resources` has type `@[R]`
_34
//
_34
let resources <- [
_34
<-create R(),
_34
<-create R()
_34
]
_34
_34
// Invalid: Reading an element from a resource array is not allowed.
_34
//
_34
let firstResource <- resources[0]
_34
_34
// Invalid: Setting an element in a resource array is not allowed,
_34
// as it would result in the loss of the current value.
_34
//
_34
resources[0] <- create R()
_34
_34
// Instead, when attempting to either read an element or update an element
_34
// in a resource array, use a swap statement with a variable to replace
_34
// the accessed element.
_34
//
_34
var res <- create R()
_34
resources[0] <-> res
_34
// `resources[0]` now contains the new resource.
_34
// `res` now contains the old resource.
_34
_34
// Use the shift statement to move the new resource into
_34
// the array at the same time that the old resource is being moved out
_34
let oldRes <- resources[0] <- create R()
_34
// The old object still needs to be handled
_34
destroy oldRes

The same applies to dictionaries.


_42
// Declare a constant for a dictionary of resources.
_42
// Create two resources and move them into the dictionary.
_42
// `resources` has type `@{String: R}`
_42
//
_42
let resources <- {
_42
"r1": <-create R(),
_42
"r2": <-create R()
_42
}
_42
_42
// Invalid: Reading an element from a resource dictionary is not allowed.
_42
// It's not obvious that an access like this would have to remove
_42
// the key from the dictionary.
_42
//
_42
let firstResource <- resources["r1"]
_42
_42
// Instead, make the removal explicit by using the `remove` function.
_42
let firstResource <- resources.remove(key: "r1")
_42
_42
// Invalid: Setting an element in a resource dictionary is not allowed,
_42
// as it would result in the loss of the current value.
_42
//
_42
resources["r1"] <- create R()
_42
_42
// Instead, when attempting to either read an element or update an element
_42
// in a resource dictionary, use a swap statement with a variable to replace
_42
// the accessed element.
_42
//
_42
// The result of a dictionary read is optional, as the given key might not
_42
// exist in the dictionary.
_42
// The types on both sides of the swap operator must be the same,
_42
// so also declare the variable as an optional.
_42
//
_42
var res: @R? <- create R()
_42
resources["r1"] <-> res
_42
// `resources["r1"]` now contains the new resource.
_42
// `res` now contains the old resource.
_42
_42
// Use the shift statement to move the new resource into
_42
// the dictionary at the same time that the old resource is being moved out
_42
let oldRes <- resources["r2"] <- create R()
_42
// The old object still needs to be handled
_42
destroy oldRes

Resources cannot be moved into arrays and dictionaries multiple times, as that would cause a duplication.


_10
let resource <- create R()
_10
_10
// Invalid: The resource variable `resource` can only be moved into the array once.
_10
//
_10
let resources <- [
_10
<-resource,
_10
<-resource
_10
]


_10
let resource <- create R()
_10
_10
// Invalid: The resource variable `resource` can only be moved into the dictionary once.
_10
let resources <- {
_10
"res1": <-resource,
_10
"res2": <-resource
_10
}

Resource arrays and dictionaries can be destroyed.


_10
let resources <- [
_10
<-create R(),
_10
<-create R()
_10
]
_10
destroy resources


_10
let resources <- {
_10
"r1": <-create R(),
_10
"r2": <-create R()
_10
}
_10
destroy resources

The variable array functions like append, insert, and remove behave like for non-resource arrays. Note however, that the result of the remove functions must be used.


_18
let resources <- [<-create R()]
_18
// `resources.length` is `1`
_18
_18
resources.append(<-create R())
_18
// `resources.length` is `2`
_18
_18
let first <- resource.remove(at: 0)
_18
// `resources.length` is `1`
_18
destroy first
_18
_18
resources.insert(at: 0, <-create R())
_18
// `resources.length` is `2`
_18
_18
// Invalid: The statement ignores the result of the call to `remove`,
_18
// which would result in a loss.
_18
resource.remove(at: 0)
_18
_18
destroy resources

The variable array function contains is not available, as it is impossible: If the resource can be passed to the contains function, it is by definition not in the array.

The variable array function concat is not available, as it would result in the duplication of resources.

The dictionary functions like insert and remove behave like for non-resource dictionaries. Note however, that the result of these functions must be used.


_18
let resources <- {"r1": <-create R()}
_18
// `resources.length` is `1`
_18
_18
let first <- resource.remove(key: "r1")
_18
// `resources.length` is `0`
_18
destroy first
_18
_18
let old <- resources.insert(key: "r1", <-create R())
_18
// `old` is nil, as there was no value for the key "r1"
_18
// `resources.length` is `1`
_18
_18
let old2 <- resources.insert(key: "r1", <-create R())
_18
// `old2` is the old value for the key "r1"
_18
// `resources.length` is `1`
_18
_18
destroy old
_18
destroy old2
_18
destroy resources

Resource Identifier

Resources have an implicit unique identifier associated with them, implemented by a predeclared public field let uuid: UInt64 on each resource.

This identifier will be automatically set when the resource is created, before the resource's initializer is called (i.e. the identifier can be used in the initializer), and will be unique even after the resource is destroyed, i.e. no two resources will ever have the same identifier.


_22
// Declare a resource without any fields.
_22
resource R {}
_22
_22
// Create two resources
_22
let r1 <- create R()
_22
let r2 <- create R()
_22
_22
// Get each resource's unique identifier
_22
let id1 = r1.uuid
_22
let id2 = r2.uuid
_22
_22
// Destroy the first resource
_22
destroy r1
_22
_22
// Create a third resource
_22
let r3 <- create R()
_22
_22
let id3 = r3.uuid
_22
_22
id1 != id2 // true
_22
id2 != id3 // true
_22
id3 != id1 // true

warning

The details of how the identifiers are generated is an implementation detail.

Do not rely on or assume any particular behaviour in Cadence programs.

Resource Owner

Resources have the implicit field let owner: PublicAccount?. If the resource is currently stored in an account, then the field contains the publicly accessible portion of the account. Otherwise the field is nil.

The field's value changes when the resource is moved from outside account storage into account storage, when it is moved from the storage of one account to the storage of another account, and when it is moved out of account storage.