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.

resource R {}

// Declare a constant for an array of resources.
// Create two resources and move them into the array.
//
let resources <- [
    <-create R(),
    <-create R()
]

// Invalid: Reading an element from a resource array is not allowed.
//
let firstResource <- resources[0]

// Invalid: Setting an element in a resource array is not allowed,
// as it would result in the loss of the current value.
//
resources[0] <- create 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.
//
var res <- create R()
resources[0] <-> res
// `resources[0]` now contains the new resource.
// `res` now contains the old resource.

// Use the shift statement to move the new resource into
// the array at the same time that the old resource is being moved out
let oldRes <- resources[0] <- create R()
// The old object still needs to be handled
destroy oldRes

The same applies to dictionaries.

// Declare a constant for a dictionary of resources.
// Create two resources and move them into the dictionary.
//
let resources <- {
    "r1": <-create R(),
    "r2": <-create R()
}

// Invalid: Reading an element from a resource dictionary is not allowed.
// It's not obvious that an access like this would have to remove
// the key from the dictionary.
//
let firstResource <- resources["r1"]

// Instead, make the removal explicit by using the `remove` function.
let firstResource <- resources.remove(key: "r1")

// Invalid: Setting an element in a resource dictionary is not allowed,
// as it would result in the loss of the current value.
//
resources["r1"] <- create R()

// Instead, 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.
//
var res <- create R()
resources["r1"] <-> res
// `resources["r1"]` now contains the new resource.
// `res` now contains the old resource.

// Use the shift statement to move the new resource into
// the dictionary at the same time that the old resource is being moved out
let oldRes <- resources["r2"] <- create R()
// The old object still needs to be handled
destroy oldRes

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

let resource <- create R()

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

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

Resource arrays and dictionaries can be destroyed.

let resources <- [
    <-create R(),
    <-create R()
]
destroy resources
let resources <- {
    "r1": <-create R(),
    "r2": <-create R()
}
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.

let resources <- [<-create R()]
// `resources.length` is `1`

resources.append(<-create R())
// `resources.length` is `2`

let first <- resource.remove(at: 0)
// `resources.length` is `1`
destroy first

resources.insert(at: 0, <-create R())
// `resources.length` is `2`

// Invalid: The statement ignores the result of the call to `remove`,
// which would result in a loss.
resource.remove(at: 0)

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.

let resources <- {"r1": <-create R()}
// `resources.length` is `1`

let first <- resource.remove(key: "r1")
// `resources.length` is `0`
destroy first

let old <- resources.insert(key: "r1", <-create R())
// `old` is nil, as there was no value for the key "r1"
// `resources.length` is `1`

let old2 <- resources.insert(key: "r1", <-create R())
// `old2` is the old value for the key "r1"
// `resources.length` is `2`

destroy old
destroy old2
destroy resources

Last updated