solidity – Passing Strings by Reference in Solidity Smart Contracts

solidity

I have two pretty simple questions:

1)

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract Test {

    function testing() public pure returns (string memory) {
        string memory x = "Hello";
        callOtherFunction(x);
        
        return x;
    }
    
    function callOtherFunction(string memory _x) internal pure {
        _x = "Goodbye";
    }
    
}

When I call testing(), it returns "Hello". Why does it not return "Goodbye"? Aren't strings passed by reference in Solidity?

  1. A second question I have is using this code:
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

contract Test {
    
    string public state_x = "Hello";

    function testingShit() public {
        callOtherFunction(state_x);
    }
    
    function callOtherFunction(string storage _x) internal {
        _x = "Goodbye";
    }
    
}

I get this error: Type literal_string is not implicitly convertible to expected type string storage pointer. What does this mean?

Thanks!

Best Answer

The string is a reference type in Solidity and references are passed by value or copied when specified as any function's argument. Think of objects in Javascript which show no changes in calling function when they are re-assigned in the called function, but any update of its properties does reflect the change. This reference is different from pointers in other languages that can be directly dereferenced with asterisk * to change the contents at pointed location in memory.

In the first case, the memory reference is reassigned, hence the change is reflected only local to the function as string's memory reference was copied. The only changes that are reflected in the calling function are when some property on the received reference is updated (like a property of struct or index of an array), but when a reference is reassigned, it points to a new memory location and the original reference in calling function remains unchanged. string type does not have any property and neither it can be updated through index but if you utilize bytes type then you can see the behavior where we are able to update properties on references which in the following case is indexes of array. But if you re-assign bytes reference then the calling function shows no changes.

contract Test {
    
    function testing() public pure returns (string memory) {
        string memory x = "Hello";
        callOtherFunction(bytes(x));

        return string(x);
    }

    function callOtherFunction(bytes memory x) internal pure {
        x[0] = bytes1('W');
        x[1] = bytes1('o');
        x[2] = bytes1('r');
        x[3] = bytes1('l');
        x[4] = bytes1('d');
    }
}

The second case is showing the same behavior, the difference is just that the Solidity compiler does not allow reassigning references pointing to contract's storage. Although, you can still update properties on the storage pointer.

contract Test {

    string public state_x = "Hello";

    function testingShit() public {
        callOtherFunction(bytes(state_x));
    }

    function callOtherFunction(bytes storage x) internal {
        x[0] = bytes1('W');
        x[1] = bytes1('o');
        x[2] = bytes1('r');
        x[3] = bytes1('l');
        x[4] = bytes1('d');
    }
}
Related Topic