.. _scoping:

Scoping and Declarations
########################

Variable Declaration
====================

The first time a variable is referenced you must declare its :ref:`type <types>`:

.. code-block:: vyper

    data: int128

In the above example, we declare the variable ``data`` with a type of ``int128``.

Depending on the active scope, an initial value may or may not be assigned:

    * For storage variables (declared in the module scope), an initial value **cannot** be set
    * For memory variables (declared within a function), an initial value **must** be set
    * For calldata variables (function input arguments), a default value **may** be given

Declaring Public Variables
--------------------------

Storage variables can be marked as ``public`` during declaration:

.. code-block:: vyper

    data: public(int128)

The compiler automatically creates getter functions for all public storage variables. For the example above, the compiler will generate a function called ``data`` that does not take any arguments and returns an ``int128``, the value of the state variable data.

For public arrays, you can only retrieve a single element via the generated getter. This mechanism exists to avoid high gas costs when returning an entire array. The getter will accept an argument to specify which element to return, for example ``data(0)``.

Declaring Immutable Variables
-----------------------------

Variables can be marked as ``immutable`` during declaration:

.. code-block:: vyper

    DATA: immutable(uint256)

    @external
    def __init__(_data: uint256):
        DATA = _data

Variables declared as immutable are similar to constants, except they are assigned a value in the constructor of the contract. Immutable values must be assigned a value at construction and cannot be assigned a value after construction.

The contract creation code generated by the compiler will modify the contract’s runtime code before it is returned by appending all values assigned to immutables to the runtime code returned by the constructor. This is important if you are comparing the runtime code generated by the compiler with the one actually stored in the blockchain.

Tuple Assignment
----------------

You cannot directly declare tuple types. However, in certain cases you can use literal tuples during assignment. For example, when a function returns multiple values:

.. code-block:: vyper

    @internal
    def foo() -> (int128, int128):
        return 2, 3

    @external
    def bar():
        a: int128 = 0
        b: int128 = 0

        # the return value of `foo` is assigned using a tuple
        (a, b) = self.foo()

        # Can also skip the parenthesis
        a, b = self.foo()


Storage Layout
==============

Storage variables are located within a smart contract at specific storage slots. By default, the compiler allocates the first variable to be stored at ``slot 0``; subsequent variables are stored in order after that.

There are cases where it is necessary to override this pattern and to allocate storage variables in custom slots. This behaviour is often required for upgradeable contracts, to ensure that both contracts (the old contract, and the new contract) store the same variable within the same slot.

This can be performed when compiling  via ``vyper`` by including the ``--storage-layout-file`` flag.

For example, consider upgrading the following contract:

.. code-block:: vyper

    # old_contract.vy
    owner: public(address)
    balanceOf: public(HashMap[address, uint256])

.. code-block:: vyper

    # new_contract.vy
    owner: public(address)
    minter: public(address)
    balanceOf: public(HashMap[address, uint256])

This would cause an issue when upgrading, as the ``balanceOf`` mapping would be located at ``slot1`` in the old contract, and ``slot2`` in the new contract.

This issue can be avoided by allocating ``balanceOf`` to ``slot1`` using the storage layout overrides. The contract can be compiled with ``vyper new_contract.vy --storage-layout-file new_contract_storage.json`` where ``new_contract_storage.json`` contains the following:

.. code-block:: json

    {
        "owner": {"type": "address", "slot": 0},
        "minter": {"type": "address", "slot": 2},
        "balanceOf": {"type": "HashMap[address, uint256]", "slot": 1}
    }

For further information on generating the storage layout, see :ref:`Storage Layout <compiler-storage-layout>`.

Scoping Rules
=============

Vyper follows C99 scoping rules. Variables are visible from the point right after their declaration until the end of the smallest block that contains the declaration.

.. _scoping-module:

Module Scope
------------

Variables and other items declared outside of a code block (functions, constants, event and struct definitions, ...), are visible even before they were declared. This means you can use module-scoped items before they are declared.

An exception to this rule is that you can only call functions that have already been declared.

Accessing Module Scope from Functions
*************************************

Values that are declared in the module scope of a contract, such as storage variables and functions, are accessed via the ``self`` object:

.. code-block:: vyper

    a: int128

    @internal
    def foo() -> int128
        return 42

    @external
    def foo() -> int128:
        b: int128 = self.foo()
        return self.a  + b

Name Shadowing
**************

It is not permitted for a memory or calldata variable to shadow the name of an immutable or constant value. The following examples will not compile:

.. code-block:: vyper

    a: constant(bool) = True

    @external
    def foo() -> bool:
        # memory variable cannot have the same name as a constant or immutable variable
        a: bool = False
        return a
.. code-block:: vyper

    a: immutable(bool)

    @external
    def __init__():
        a = True
    @external
    def foo(a:bool) -> bool:
        # input argument cannot have the same name as a constant or immutable variable
        return a

Function Scope
--------------

Variables that are declared within a function, or given as function input arguments, are visible within the body of that function. For example, the following contract is valid because each declaration of ``a`` only exists within one function's body.

.. code-block:: vyper

    @external
    def foo(a: int128):
        pass

    @external
    def bar(a: uint256):
        pass

    @external
    def baz():
        a: bool = True

The following examples will not compile:

.. code-block:: vyper

    @external
    def foo(a: int128):
        # `a` has already been declared as an input argument
        a: int128 = 21

.. code-block:: vyper

    @external
    def foo(a: int128):
        a = 4

    @external
    def bar():
        # `a` has not been declared within this function
        a += 12

.. _scoping-block:

Block Scopes
------------

Logical blocks created by ``for`` and ``if`` statements have their own scope. For example, the following contract is valid because ``x`` only exists within the block scopes for each branch of the ``if`` statement:

.. code-block:: vyper

    @external
    def foo(a: bool) -> int128:
        if a:
            x: int128 = 3
        else:
            x: bool = False

In a ``for`` statement, the target variable exists within the scope of the loop. For example, the following contract is valid because ``i`` is no longer available upon exiting the loop:

.. code-block:: vyper

    @external
    def foo(a: bool) -> int128:
        for i in [1, 2, 3]:
            pass
        i: bool = False

The following contract fails to compile because ``a`` has not been declared outside of the loop.

.. code-block:: vyper

    @external
    def foo(a: bool) -> int128:
        for i in [1, 2, 3]:
            a: int128 = i
        a += 3
