11

I want to implement a contract like the ERC20Detailed.sol example from open Zeppelin:

My question: why setting a private variable and then, creating a getter for the same variable when the solidity compiler can automatically create the getter for a public variable ?

According to Solidity: private vs public variables it seams there is no advantage of doing that.

Am I missing something ?

1
  • 3
    If you want contract B to know contract A only by its interface, then the only way for contract B to read a variable in contract A, is by calling a getter function in A, which returns this variable. The auto-generated getter of the variable is not going to help you because it is auto-generated in the contract only, not in the interface. And of course, you cannot declare it in the interface, because it is auto-generated in the contract as public, and interface functions can only be exetrnal. Feb 15, 2019 at 22:19

3 Answers 3

9

I see good observations about style but I didn't see the safety aspect.

Setting a variable to private ensures that it can only be manipulated via functions in the contract designed for that purpose and never by a successor contract that inherited it.

That means an errant contract could not accidentally zero out, say, owner ... a potentially disastrous accident that is preventable with private.

So, it's worth considering for vital state elements.

Hope it helps.

UPDATE

    pragma solidity 0.4.25;
    
    contract Risky {
        
        string public vital;
        
        constructor() public {
            vital = "do not change";
        }
    }
    
    contract Careless is Risky {
        
        function oops() public {
            
            /*
            Since vital is "public", this child contract is free to write to it.
            This is not ideal because it could lead to critical values overwritten.
            This child contract is free to make mistakes that could be disasterous.
            */
            
            vital = "game over";
        }
    }
    
    /*
    ----------------------------------------
    Using private for safety
    ----------------------------------------
    */
    
    contract Cautious {
        
        string private vital;
        
        constructor() public {
            vital = "cannot be changed by accident";
        }
        
        function getVital() public view returns(string) {
            return vital;
        }
        
        function setVital(string youKnowWhatYoureDoing) public {
            vital = youKnowWhatYoureDoing;
        }
    }
    
    contract Isolated is Cautious {
        
        /* 
        This child cannot stomp on Cautious' "vital" even if it wants to because it's not "public" or "internal". 
        It *must* use Cautious' getter and setter functions which means Cautious is in control. 
        */
        
    }
5
  • 2
    Sincerely this is very difficult to understand: apparently any public variable is not writable by its getter, of course, neither writable by other contracts, which can only access it by the public getter in reading only. Could you please explain more?
    – Rick Park
    Feb 16, 2019 at 7:35
  • 2
    public does multiple things. The "free" getter is one of those things. It also changes the scope and makes it vulnerable to overwrite by contracts that inherit from it. That may not be desirable. I added an example to help illustrate the point. Feb 16, 2019 at 20:36
  • 1
    Do You mean errors due to poor programming, before deploying?
    – Rick Park
    Feb 16, 2019 at 22:43
  • 1
    Yes. It's about preventing errors in the code. Feb 17, 2019 at 0:53
  • 1
    Thank you, it is an interesting point of view.
    – Rick Park
    Feb 17, 2019 at 0:54
3

I can't speak for others, but the reason I do it is for naming. A public variable in Solidity will create a getter with the same name (so a public variable named totalSupply would require calling the function totalSupply() to get the value). Calling a variable name is a little misleading for most people as it's against how most languages work, when they would just access it as .totalSupply. Making the variable private and creating a better named function (getTotalSupply() in this example) is just more intuitive to myself and most others.

2

The difference can be in the way you access the variable and in the permission scheme.

ACCESSING

1 - If you have a public state variable of array type, then you can only retrieve single elements of the array via the generated getter function. This mechanism exists to avoid high gas costs when returning an entire array. You can use arguments to specify which individual element to return, for example data(0). If you want to return an entire array in one call, then you need to write a function, for example:

pragma solidity >=0.4.0 <0.6.0;

contract arrayExample {
  // public state variable
  uint[] public myArray;

  // Getter function generated by the compiler
  /*
  function myArray(uint i) returns (uint) {
      return myArray[i];
  }
  */

  // function that returns entire array
  function getArray() returns (uint[] memory) {
      return myArray;
  }
}

Now you can use getArray() to retrieve the entire array, instead of myArray(i), which returns a single element per call.

2 - Moreover may be you need some particular elaboration before accessing: for instance to return int being the variable uint or so.

3 - Another important use case that I know very well is when many “copies” of the public variable exist in different contracts talking each other (multicontracts applications). In that a case you can ask your getter to sync and update the variable value before to return it.

4 - etc.

PERMISSIONS

A public variable generates a public getter, without any permission scheme possible: it is accessible by anyone.

On the contrary, you can reserve the getter written by you to classes of users, for instance inserted in some white list and/or being EOA and/or being not EOA and so on: it is up to you.

-> About comments about “pointless permissions”: yes you can still (ever) access a variable even if private, no doubts about it, but if you prevent the custom getter to do it by some require, you cannot do it easily if you cannot satisfy that require, in any case it is not just a matter of one call. And, in particular, it can be not accessible by other contracts! This does not mean that it is “secret”, it means that it remains “under the hood” for your users. You need a blockchain investigation and proper tools to access it. And for the majority of applications, this is definitively enough!

In short: It is a matter of use cases.

7
  • 1
    Access control isn't a great reason IMO, since it's all public on-chain data anyway. Anyone can still read the data if there's access control in the getter.
    – natewelch_
    Feb 15, 2019 at 17:08
  • I don’t think so. If you have a private variable and a getter which require your address being odd or even or whatever, you cannot read it if your address is not odd or even or whatever. Of course you can access the variable at a forensic investigation level... but what does it mean ? Nothing at all.
    – Rick Park
    Feb 15, 2019 at 17:10
  • The fact that it's on-chain means the access control for reading data is pointless since you can read the data anyway.
    – natewelch_
    Feb 15, 2019 at 17:13
  • Why do you need a getter, then? You can read the block directly! 😉
    – Rick Park
    Feb 15, 2019 at 17:52
  • I'm in agreement with Nate. The access control reason is not a valid one and contrary to what Rick claims, you can have a smart contract retrieve whatever storage slots it wants. . You can bypass the require readily by using assembly to access the storage slot directly. Plentiful working cut-and-paste solutions exist, e.g. ethereum.stackexchange.com/a/80534/55116. May 26, 2021 at 14:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.