Purity

A function is pure if it does not access any persistent storage. Conversely, the function is impure if it does access any storage. Naturally, as storage is only available in smart contracts, impure functions cannot be used in predicates, scripts, or libraries. A pure function cannot call an impure function.

In Sway, functions are pure by default but can be opted into impurity via the storage function attribute. The storage attribute may take read and/or write arguments indicating which type of access the function requires.

#[storage(read)]
fn get_amount() -> u64 {
    ...
}

#[storage(read, write)]
fn increment_amount(increment: u64) -> u64 {
    ...
}

Note: the #[storage(write)] attribute also permits a function to read from storage. This is due to the fact that partially writing a storage slot requires first reading the slot.

Impure functions which call other impure functions must have at least the same storage privileges or a superset of those for the function called. For example, to call a function with write access a caller must also have write access, or both read and write access. To call a function with read and write access the caller must also have both privileges.

The storage attribute may also be applied to methods and associated functions, trait and ABI declarations.

A pure function gives you some guarantees: you will not incur excessive storage gas costs, the compiler can apply additional optimizations, and they are generally easy to reason about and audit. A similar concept exists in Solidity. Note that Solidity refers to contract storage as contract state, and in the Sway/Fuel ecosystem, these two terms are largely interchangeable.