Scope of State Variables

We can only control the scope of state variables but we can’t do the same with local and global variables. So every state variable has some level of scope associated with it i.e. to what extent it will be accessible. In solidity, we can define a scope by using the following access modifiers for state variables:

  1. Public.
  2. Internal.
  3. Private.

Note : There are total 4 types of access modifiers but only 3 of them can be applied on variables.

These access modifiers are used to limit the variable’s access throughout various contracts but the data can be accessed & viewed by anyone on the blockchain publicly. 

Syntax:

<data-type> <access-modifier> <var-name>;

1. Public 

The public access modifier makes the variable accessible inside the contract, sub-contracts, and outside of it as well. Meaning, we can access the public variables in other contracts as well, doesn’t matter if they are derived or not. And For every state variable declared as public, there is a get() function created by solidity automatically.  

2. Internal

This access modifier defines the scope which allows the state variables to be accessed only in the contract itself and all the contracts that are derived from it. All the sub-contracts can access the state variables which are declared as ‘internal’. But external contracts can’t access the internal state variables.

3. Private

State variables declared by the use of private access modifiers are limited only to the contract in which they are defined.

Below is the example to show all types of scopes given by each of the access modified with a code example:

Solidity




// SPDX-License-Identifier: MIT
pragma solidity >= 0.5.0 < 0.9.0;
  
contract BaseContract {
    
  // Public state variable
  string public message = "Hello Geek!"
    
  // Internal State variable
  uint internal age = 22; 
    
  // Private state variable
  string private messageTwo = "This is a private variable"
  
  // I haven't defined a get() for message variable as 
  // solidity automatically defines it for 'public' 
  // state variables
  function getAge() public view returns (uint) 
  {
    return age;
  }
    
  function getMessageTwo() public view returns (string memory) 
  {
    return messageTwo;
  }
}
  
contract DerivedContract is BaseContract {
    
  // No Error because, public State Variables 
  // are accessible anywhere.
  function getMessageFromBase() public view returns (string memory) 
  {
    return message;     
  }
    
  // No Error because, internal State Variables are accessible 
  // directly inside derived Contracts.
  function getAgefromBase() public view returns (uint) 
  {
    return age;     
  }
    
  // Compiler Error : Can't access private state variables 
  // in derived contract.
  function getMessageTwo() public view returns (string) 
  {
    return messageTwo;  
  }
}
  
contract ExternalContract {
    
  // We'll need an object to access the public variables.
  BaseContract baseContract = new BaseContract(); 
    
  // public State Variables are accessible by the use 
  // of object in external contracts.
  function getExternalMessageFromBase() public view returns (string memory) 
  {
    return string(abi.encodePacked(baseContract.message));     
  }
  
  // internal State Variables are NOT accessible by the 
  // use of object in external contracts.
  function getNum() public view returns (uint) 
  {
    return baseContract.age;     
  }
    
  // Compiler Error : Can't access private state variables 
  // in External contracts either.
  function getMessageTwo() public view returns (string memory) 
  {
    return baseContract.messageTwo;  
  }
}


Explanation: In the above code, 3 contracts are created: Base Contract, Derived Contract, and External Contract. The Base Contract consists of 3 state variables defined with different access-modifier. Since the message is a public variable, it will be accessible anywhere but in external contracts, you’ll require an object of Base Contract to access it. 

Note: The string data-type is used, due to which there is a need to perform type conversion and its done by the following line: 

string(abi.encodePacked(var-name). 

The data type like – byte32 can also be used , then there is no need to perform this type conversion.

The internal variables will only be accessed in the contract in which they are defined and the inherited ones and the private ones will only be accessible in the contract in which they are defined.

Solidity – State Variables

Any variable created at the contract level is called the state variable (variables that aren’t inside a function) and it is stored permanently on the blockchain i.e., they are persistent and cannot be deleted. So, if you were to create a state variable in your contract and assign it some value, and came back after some time then its value would still be the same.  An important thing to note here is, you’ll have to pay some level of gas for every state variable declared. Hence, you should be careful every time you create a state variable. 

Note: Gas is a fee that is required to execute each transaction. Just like we need fuel to run a vehicle, we also need gas to execute the transactions on the blockchain. And the price of gas is calculated by the supply and the demand of miners in the network.

Important Points:

  • State variables directly store data on the blockchain that is, on the contract storage itself. So, if you were to store data in the state variable and come back after 1-week then your data would still be there.
  • State variables are declared inside a contract and outside the function.
  • Solidity automatically creates a get method with the same name for state variables.
  • The state variable can be assigned one of the access modifiers: public, internal, or private.
  • Since storages are not allocated dynamically, we’ve to re-compile each time we declare a state variable.
  • State variables are expensive as they cost gas.
  • Every instance of a contract will contain only those state variables, which were present in the contract before compilation.

Example:

Solidity




// SPDX-License-Identifier: MIT
pragma solidity >= 0.5.0 < 0.9.0;
  
contract w3wiki {
    // Created inside the contract 
    // but outside a function
    string public message; 
    
    function setMessage() public {
        message = "Hello Geek !";
    }
}


Explanation: In the above code, we’ve created a state variable – ‘message’ and its value is set to “Hello Geek !” through the set() function. Since we’ve used the access modifier as public, the solidity will automatically create a public get() function to get the value of the message variable which allows everyone to read the value of the message variable even from outside the contract.

Similar Reads

Scope of State Variables

...

Initialization of State Variable

We can only control the scope of state variables but we can’t do the same with local and global variables. So every state variable has some level of scope associated with it i.e. to what extent it will be accessible. In solidity, we can define a scope by using the following access modifiers for state variables:...

Reading and Writing to a State Variable

...

State Variables vs Local Variables

Now let’s see how many ways we can initialize a state variable. There are three ways in which one can initialize a state variable:...