2

suppose I have the defined a struct in solidity as below

    struct Organisation {
    string name;
    address ethAddress;
    uint rating;
    string regNumber;
}

I have defined an dynamic array of the above struct as

//  list of all insurers/Organisations

Organisation[] allOrgs;

If i need to pass the element of this array to a internal function which is actually just comparing the value against another value, will it be passed by reference?

function getInsurerEth(string uname) public payable returns(address) {
    for(uint i = 0; i < allOrgs.length; ++ i) {
        if(stringsEqual(allOrgs[i].name, uname)) {
            return allOrgs[i].ethAddress;
        }
    }
}

The function StringsEqual defined as below. I need to know if the first parameter is passed by reference or value. If by value, then I can actually remove the argument attribute 'storage' and make the function pure. Also note that this is a internal function call which will use the jump opcode and also i am not editing the storage element allOrgs[i].name.

    //   internal function to compare strings

function stringsEqual(string storage _a, string memory _b) internal returns (bool) {
    bytes storage a = bytes(_a);
    bytes memory b = bytes(_b);
    if (a.length != b.length)
        return false;
    // @todo unroll this loop
    for (uint i = 0; i < a.length; i ++)
    {
        if (a[i] != b[i])
            return false;
    }
    return true;
}
1

The first argument of function StringsEqual is passed by reference and not by value because you are explicitly specifying state variable _a in storage.

To declare function StringsEqual as pure you need to pass an argument by value as following -

function stringsEqual(string memory _a, string memory _b) internal pure returns (bool) {
    bytes memory a = bytes(_a);
    bytes memory b = bytes(_b);
    if (a.length != b.length)
        return false;
    // @todo unroll this loop
    for (uint i = 0; i < a.length; i ++)
    {
        if (a[i] != b[i])
            return false;
    }
    return true;

}   

To conclude: when you are explicitly defining storage type of an argument asstorage you are passing an argument to a function by reference.

If you don't specify storage type of a function argument then function arguments are always in memory and you are passing an argument to a function by value.

To add further clarification I tried following :

function stringsEqual(string storage  _a, string  _b) internal  returns (bool) {
    bytes memory a = bytes(_a);
    bytes memory b = bytes(_b);
    if (a.length != b.length)
        return false;
    // @todo unroll this loop
    for (uint i = 0; i < a.length; i ++)
    {
        if (a[i] != b[i])
            return false;
    }
    _a = "xyz";
    _b = "xyz";
    return true;

} 

And I get the following error which confirms that argument is passed by reference :

browser/pass_by_reference_value.sol:198:14: TypeError: Type literal_string "xyz" is not implicitly convertible to expected type string storage pointer.

  • This means that if I change the parameter a to memory instead of storage, it will work fine as i am not actually making any state changes to the state variable. – Joseph T F Sep 7 '18 at 9:04
  • Yes, it will work fine – Soham Lawar Sep 7 '18 at 9:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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