1

I'm trying to implement a simple "pop" function in solidity, and I am getting very different behaviour with string values depending on whether or not I name the returns value in the function declaration.

contract PopArray {
    string[] public string_arr;

    function PopArray() {
        // fill the array with some data
        string_arr = ['zero', 'one', 'two', 'three', 'four'];
    }

    // Calling this once returns 'four', calling it a second time returns 'three', etc. 
    function pop_string () returns (string member) {
        member = string_arr[string_arr.length-1]; //get the last value
        string_arr.length = string_arr.length-1;  // reduce the length of the array
        return member;
    } 

    // Calling this returns nothing, but does reduce the length of the array.
    function broken_pop_string () returns (string) {
        string member = string_arr[string_arr.length-1];
        string_arr.length = string_arr.length-1;
        return member;
    }
}

Here is how the results look in remix when I call one function, then the other : enter image description here

Conversely, with other types I've checked, a value is returned regardless of whether the return value is named in the function declaration. Here is some code trying this out with uint and bytes32 values.

Is there a subtlety regarding strings that I'm missing here?

1 Answer 1

1

If I'm not mistaken, the subtlety you've hit upon is Reference variables, because member is going to be a pointer instead of a unique memory var as you might expect.

Again, if I'm not mistaken, after you shorten the array, the reference pointer refers to a non-existent member of the array, so some unexpected behavior.

See here: http://vessenes.com/solidity-frustrations-references-and-mapping/

These Reference types emerge when the value requires further analysis, e.g. array index or mapping index. You get a pointer to an existing value instead of a new named variable/value.

5
  • Thank you, it seems you are right. Logging the value of member before and after shortening the array verifies it. Also, adding memory fixes the behaviour so that the string value is returned. (ie. string memory member = string_arr[string_arr.length-1];)
    – maurelian
    Commented Mar 21, 2017 at 18:13
  • Thanks for sharing your observations. It's quite useful as this subtlety leads to non-obvious outcomes. From PV - "We are in a world where a tiny code error may not be easily fixable. In that world, this is a very annoying language feature, one that could cause real problems." Commented Mar 21, 2017 at 18:22
  • I'm still a little confused actually. This part of your answer makes sense to me: > These Reference types emerge when the value requires further analysis, e.g. array index or mapping index. But then why shouldn't variables pointing to an array element containing a bool, uint, and bytes32 not behave the same way? I can't find any reference to this difference in the docs, so am tempted to characterize this inconsistency as a bug. What do you think?
    – maurelian
    Commented Mar 21, 2017 at 18:41
  • 1
    I might urge you to do that. Even a "not a bug" explanation might provide some clarification. I'd be a big fan if that sort of clarity turned up in this thread. I'm certain a lot of Solidity devs are unsure about this. It seems rather important to understand. Commented Mar 22, 2017 at 1:18
  • github.com/ethereum/solidity/issues/1812
    – maurelian
    Commented Mar 22, 2017 at 9:43

Your Answer

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

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