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.
Before the closing bracket of a function that has resources created or moved into scope, those resources must explicitly be either moved to a valid storage location 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 behavior 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.
Declare a resource named SomeResource
, with a variable-integer field:
Declare a constant with a value of resource type SomeResource
:
Move the resource value to a new constant:
Declare a function that accepts a resource. The parameter has a resource type, so the type annotation must be prefixed with @
:
Call function use
, and move the resource into it:
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
:
Declare another, unrelated value of resource type SomeResource
:
Destroy the resource referred to by constant d
:
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 @
:
Declare a function that consumes a resource and destroys it. The parameter has a resource type, so the type annotation must be prefixed with @
:
Declare a function that 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.
Resources must be used exactly once.
Declare a function that consumes a resource but does not use it:
Declare a constant named res
that has the resource type SomeResource
:
Call the function use
and move the resource res
into it:
Declare a function that has a resource parameter:
Declare a function which has a resource parameter:
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 that has a resource parameter:
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:
Instead, use a swap statement:
Or, use the shift statement (<- target <-
):
Nested resources
Fields in composite types behave differently when they have a resource type.
Accessing a field or calling a 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. For example:
Instead, use a swap statement:
When a resource containing nested resources in fields is destroyed with a destroy
statement, all the nested resources are also destroyed:
The order in which the nested resources are destroyed is deterministic but unspecified, and cannot be influenced by the developer. In this example, when Parent
is destroyed, the child1
and child2
fields are also both destroyed in some unspecified order.
In previous versions of Cadence, it was possible to define a special destroy
function that would execute arbitrary code when a resource was destroyed, but this is no longer the case.
Destroy events
While it is not possible to specify arbitrary code to execute upon the destruction of a resource, it is possible to specify a special event to be automatically emitted when a resource is destroyed. The event has a reserved name — ResourceDestroyed
— and it uses a special syntax:
Whenever a value of type R
defined this way is destroyed, a special R.ResourceDestroyed
event is emitted. The special syntax used in the definition of the ResourceDestroyed
specifies what the values associated with each event parameter will be; in this case, the id
field of the R.ResourceDestroyed
event will be the value that the id
field held immediately before the resource was destroyed. In general, for a ResourceDestroyed
event defined as:
- The value of
field1
on the event will be the result of evaluatinge1
before destroying the resource. - The value of
field2
on the event will be the result of evaluatinge2
before destroying the resource, and so on.
As one might expect, e1
and e2
must also be expressions of type T1
and T2
, respectively.
In order to guarantee that these events can be emitted with no chance of failure at runtime, there are restrictions placed on which kinds of types and expressions can be used in their definitions. In general, an expression defining the value of a field (the e
in the general definition above) can only be a member or indexed access on self
(or, base
in the case of an attachment), or a literal. The types of event fields are restricted to number types, String
s, Boolean
s, Address
es, and Path
s.
Resources in closures
Resources cannot be captured in closures, as that could potentially result in duplications:
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.
Declare a constant for an array of resources. Then, create two resources and move them into the array (resources
has type @[R]
):
Instead, when attempting to either read an element or update an element in a resource array, use a swap statement with a variable to replace the accessed element:
Use the shift statement to move the new resource into the array at the same time that the old resource is being moved out:
The same applies to dictionaries.
Declare a constant for a dictionary of resources. Then, create two resources and move them into the dictionary (resources
has type @{String: R}
):
Instead, make the removal explicit by using the remove
function:
When attempting to either read an element or update an element in a resource dictionary, use a swap statement with a variable to replace the accessed element.
The result of a dictionary read is optional, as the given key might not exist in the dictionary. The types on both sides of the swap operator must be the same, so also declare the variable as an optional:
Use the shift statement to move the new resource into the dictionary at the same time that the old resource is being moved out:
Resources cannot be moved into arrays and dictionaries multiple times, as that would cause a duplication:
Resource arrays and dictionaries can be destroyed:
The variable array functions, like append
, insert
, and remove
, behave like non-resource arrays. Please note, however, that the result of the remove
functions must be used:
- The variable array function
contains
is not available, as it is impossible: if the resource can be passed to thecontains
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
andremove
behave like non-resource dictionaries. Please note, however, that the result of these functions must be used:
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 is 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).
-
Declare a resource without any fields:
-
Create two resources:
-
Get each resource's unique identifier:
-
Destroy the first resource:
-
Create a third resource:
The details of how the identifiers are generated is an implementation detail.
Do not rely on or assume any particular behavior in Cadence programs.
Resource owner
Resources have the implicit field let owner: &Account?
. 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.