What are Visibility Modifiers in Solidity ?

What are Visibility Modifiers in Solidity ?

In this article , I'll be letting you the know how the visibility modifiers are used and what is the restriction of each modifier in a program.

Introduction :

The visibility modifiers would determine the level of access of a variable or function in our smart contracts . These are also called as "Access Modifiers" . These modifiers are necessary to protect which smart contract can see the data and the behavior of given smart contract.

The solidity has 3 levels of visibility for state variables and 4 levels of visibility for functions .

Visibility of State Variables in solidity :

The 3 visibility modifiers which are present in the state variables are

  • public
  • internal
  • private

Public :

In public modifier the variables can be accessed by the contract and by other smart contracts . In general , for calling the values of the state variables in solidity we use to create a getter function and call it . But after introducing the public modifier the getter function is automatically created by default . Moreover , it can be accessed easily same as functions in the smart contracts . Lets see the practical implementation of it .

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract bytecode{

    string name = "Amar";
    uint age = 23;
    string hobbie = "writing";

function getname() public view returns(string memory){
      return (name);

}
function getage() public  view returns(uint ){
      return (age);

}
function gethobbie() public  view returns(string memory ){
      return (hobbie);

}
}

The output of the above code is

pic1.jpg

Now lets try to achieve the same output in the simpler way

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract bytecode{
    string public name = "Amar";
    uint public age = 23;
    string public hobbie = "writing";
}

output :

pic2.jpg

In this way the modifiers are used and make our way more easier & simpler .

Note : when you initialize the variable with public then we can call the variables with any user address as it has no restrictions in access .

Internal :

This type of modifiers can only be used with in the contract it is defined in and its subclasses . As it has some limitations compared to public modifier .

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract bytecode{

    string internal name = "Amar";
    uint internal age = 23;
    string internal hobbie = "writing";

}

output of the contract is

pic3.jpg

As we can see that their is no output for the contract because the remix IDE comes under external and the variables limit is bound to be only in the smart contract .

Lets try to access the variable from another smart contract and display the value of variable by using the concept of inheritance . The code :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract bytecode1{

    string private name = "Amar";
     uint internal age = 23;
    string public hobbie = "writing";

}

contract bytecode2 is bytecode1 {
     uint public _age = age ;
}

The output of the code is

pic4.jpg

In this way to restrict the access based on our usability we use the modifier internal .

Private :

Private means the variable can only be accessed within the contract it is defined . Incase , if we try to access it outside of the contract then we get a compilation error .

Visibility of Functions in solidity :

The access modifiers present in solidity are 4 . They are :

  • Public
  • Private
  • Internal
  • External

Lets see the limits of all the modifiers in a tabular format .

PIC5.jpg

In this way the modifiers restrictions are categorized based on its types .

The public modifier has no restrictions and can be called by any smart contract as it has no limits .

In functions the access modifiers are must and should be declared . Incase of not used then we get an error that the visibility is not defined .

Lets see the usage of all the modifiers in a smart contract :

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{

  function f1() public pure returns(uint ){
        return 1;
        }
        function f2() private pure returns(uint ){
        return 2;
        }
        function f3() internal pure returns(uint ){
        return 3;
        }
        function f4() external pure returns(uint ){
        return 4;
        }
}

The output of the code is as follows

pic6.jpg

As we can see that only the functions which are declared as public and external are only visible as they are having the access as outside (as per table ) So they are visible in the remix output .

External :

An external function can be accessed from other contracts using transactions and this type of functions can be accessed using the this.functionName() notation.

Note : The modifier external cannot be accessed with in the smart contract as it produces the error .

Code:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{
        function f2() public pure returns(uint ){
        uint x = f4();
        return x;
        }
        function f4() external pure returns(uint ){
        return 4;
        }
}

In this way if we try to access the external with in the contract then we get the compilation error . Not only that but also if we try to access it from other smart contract by the concept of inheritance also we get an error .

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{    
        function f4() external pure returns(uint ){
        return 4;
        }
}
contract B is A{
      uint public bx= f4();
}

In order to use the external functions inside a derived smart contract then we need to create a object of that contract and then access the value of it .

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{    
        function f4() external pure returns(uint ){
        return 4;
        }
}
contract B is A{
      A obj = new A();
      uint public bx= obj.f4();
}

If we try to execute it then we can see the output of the value bx.

pic7.jpg

So in this way the external modifier is used inside a smart contract based on the requirement .

Internal :

The internal functions can be accessed in the contract in which it is defined and in its subclasses. It is same like the internal in the state variables.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{    
        function f3() internal pure returns(uint ){
        return 4;
        }
}
contract B is A{
     uint public bx=f3();
}

The output of the smart contract is

pic8.jpg

In this way the internal modifiers are used in a smart contract .

Private :

The private function can only be called from the contract in which it is defined .

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract A{   
       uint public num = f3();
         function f3() private pure returns(uint ){
        return 4;
        }
}

The output is

pic9.jpg

Conclusion:

The solidity's visibility modifiers are a little different from those of other languages , but they still work mostly like other programming languages . This concept has to be definitely learned in order to write a pretty good smart contract . Especially external functions , which can make a huge difference in gas consumption .


If you have any questions or suggestions, feel free to reach out to me! 😊

🕊️Twitter : twitter.com/DMohindar

📩 Email :

🔗LinkedIn : linkedin.com/in/mohindar-amarnadh-b77a28150