solidity/docs/contracts/constant-state-variables.rst
2023-07-14 15:29:32 +02:00

112 lines
5.0 KiB
ReStructuredText

.. index:: ! constant
.. _constants:
**************************************
Constant and Immutable State Variables
**************************************
State variables can be declared as ``constant`` or ``immutable``.
In both cases, the variables cannot be modified after the contract has been constructed.
For ``constant`` variables, the value has to be fixed at compile-time, while
for ``immutable``, it can still be assigned at construction time.
It is also possible to define ``constant`` variables at the file level.
The compiler does not reserve a storage slot for these variables, and every occurrence is
replaced by the respective value.
Compared to regular state variables, the gas costs of constant and immutable variables
are much lower. For a constant variable, the expression assigned to it is copied to
all the places where it is accessed and also re-evaluated each time. This allows for local
optimizations. Immutable variables are evaluated once at construction time and their value
is copied to all the places in the code where they are accessed. For these values,
32 bytes are reserved, even if they would fit in fewer bytes. Due to this, constant values
can sometimes be cheaper than immutable values.
Not all types for constants and immutables are implemented at this time. The only supported types are
:ref:`strings <strings>` (only for constants) and :ref:`value types <value-types>`.
.. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.21;
uint constant X = 32**22 + 8;
contract C {
string constant TEXT = "abc";
bytes32 constant MY_HASH = keccak256("abc");
uint immutable decimals = 18;
uint immutable maxBalance;
address immutable owner = msg.sender;
constructor(uint decimals_, address ref) {
if (decimals_ != 0)
// Immutables are only immutable when deployed.
// At construction time they can be assigned to any number of times.
decimals = decimals_;
// Assignments to immutables can even access the environment.
maxBalance = ref.balance;
}
function isBalanceTooHigh(address other) public view returns (bool) {
return other.balance > maxBalance;
}
}
Constant
========
For ``constant`` variables, the value has to be a constant at compile time and it has to be
assigned where the variable is declared. Any expression
that accesses storage, blockchain data (e.g. ``block.timestamp``, ``address(this).balance`` or
``block.number``) or
execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions
that might have a side-effect on memory allocation are allowed, but those that
might have a side-effect on other memory objects are not. The built-in functions
``keccak256``, ``sha256``, ``ripemd160``, ``ecrecover``, ``addmod`` and ``mulmod``
are allowed (even though, with the exception of ``keccak256``, they do call external contracts).
The reason behind allowing side-effects on the memory allocator is that it
should be possible to construct complex objects like e.g. lookup-tables.
This feature is not yet fully usable.
Immutable
=========
Variables declared as ``immutable`` are a bit less restricted than those
declared as ``constant``: Immutable variables can be assigned a
value at construction time.
The value can be changed at any time before deployment and then it becomes permanent.
One additional restriction is that immutables can only be assigned to inside expressions for which
there is no possibility of being executed after creation.
This excludes all modifier definitions and functions other than constructors.
There are no restrictions on reading immutable variables.
The read is even allowed to happen before the variable is written to for the first time because variables in
Solidity always have a well-defined initial value.
For this reason it is also allowed to never explicitly assign a value to an immutable.
.. warning::
When accessing immutables at construction time, please keep the :ref:`initialization order
<state-variable-initialization-order>` in mind.
Even if you provide an explicit initializer, some expressions may end up being evaluated before
that initializer, especially when they are at a different level in inheritance hierarchy.
.. note::
Before Solidity 0.8.21 initialization of immutable variables was more restrictive.
Such variables had to be initialized exactly once at construction time and could not be read
before then.
The contract creation code generated by the compiler will modify the
contract's runtime code before it is returned by replacing all references
to immutables with the values assigned to them. This is important if
you are comparing the
runtime code generated by the compiler with the one actually stored in the
blockchain. The compiler outputs where these immutables are located in the deployed bytecode
in the ``immutableReferences`` field of the :ref:`compiler JSON standard output <compiler-api>`.