[Ethereum] Should I give names to return values, when a function returns several of them

conventionssolidity

I am currently working with solc v0.4.25, where it is not possible to return structures, so the only way to return multiple values is in a tuple.

I've been advised to give names to each one of the returned values, in order to make the code easier to read and less prone to errors.

However, it would ultimately force me to give names to every return value in my system, even when only a single value is returned.

In order to clarify the above, here are two examples:

function withoutNames(uint x) pure returns (uint, uint) {
    uint y = 2 * x;
    uint z = 3 * x;
    return (y, z);
}

function withNames(uint x) pure returns (uint y, uint z) {
    y = 2 * x;
    z = 3 * x;
}

My question:

Is there an official coding convention (or an accepted standard among the community) for how to deal with return-value naming?

The way I see it, the options are:

  1. Do not name any return value
  2. Name every return value in every function
  3. Name every return value in every function which returns more than one value

Thank you very much for your suggestions.

Best Answer

Short answer:

The "returned byte buffer" of both methods is exactly the same.

The only difference is the generated contract ABI JSON file which can be used by "external" contract callers ( js / php / python / etc ) to assign variable name to our method's return automatically.

Ie:

   var callResultWithNames = await contract.methods.withNames(1).call();
   var y = callResultWithNames.y;
   var z = callResultWithNames.z;

   // array indexing also works
   // var y = callResultWithNames[0];
   // var z = callResultWithNames[1];

Versus

   var callResultWithoutNames = await contract.methods.withoutNames(1).call();
   var y = callResultWithoutNames[0];
   var z = callResultWithoutNames[1];

Detailed answer:

Web3 calls

function withoutNames(uint x) public pure returns (uint, uint);

ABI JSON ->
    "name": "withoutNames",
    "outputs": [
        {
            "name": "",       <<<<
            "type": "uint256"
        },
        {
            "name": "",       <<<<
            "type": "uint256"
        }
    ],
function withNames(uint x) public pure returns (uint y, uint z);

ABI JSON ->
    "name": "withNames",
    "outputs": [
        {
            "name": "y",      <<<<
            "type": "uint256"
        },
        {
            "name": "z",      <<<<
            "type": "uint256"
        }
    ],

Solidity calls

When talking about calling such a method from within a contract directly in solidity code, we're already assigning the returned values to variables ( a ) or reading the returned buffer through assembly using a staticcall ( b ), in which case we don't need the variable names.

a) in code

var x,y = contract.withoutNames(1);

b) in assembly

    assembly {
        let success := staticcall(
                                500000,             // Gas to use for this call
                                toAddress ,         // To addr
                                callBufferPointer,  // Inputs are stored at current ptr location
                                callDataLength,     // input length
                                0,          
                                0)          
        // copy result byte size from return value ( ignore first 32 bytes ) ( next 32 bytes )
        returndatacopy( 
            thisOutputPointer,
            0, 
            returndatasize() 
        )
        // manipulate and use the returned data stored at thisOutputPointer address any way we want.
    }

Notes

Even thou having the names of the returned values in the function declaration result in automatic generation of these objects when loaded by web3, I personally find it very distracting when reading the code step by step and usually prefer my return statements at the end of a method.