8

I have a function that gets an address array from another contract, conditionally deletes the msg.sender from the array, then saves the new array back to that contract.

Because the array backerList is in memory, i can't do backerList.length--;

But I cannot declare backerList as a storage array because memory array can't be converted to a storage one.

I am stuck here, what should I do?

 address[] memory backerList = syndicate.getBackerList();

 if(syndicate.individualTotalBacking(msg.sender) == 0){

        uint index;

        for(uint i=0; i<backerList.length; i++){
            if (backerList[i] == msg.sender){
                index = i;
            }

        //shifting array

            for(uint k=index; k<backerList.length-1; k++){
                backerList[k]=backerList[k+1];
            }

        }

        backerList.length--;
        syndicate.setBackerList(backerList);
    } else {}
4
  • What is the function signature of setBackerList?
    – Jesbus
    Commented Jun 23, 2018 at 10:03
  • setBackerList basically pass backerList[ ] to another contract called syndicate. I dont think this is the issue to be honest. Commented Jun 23, 2018 at 10:20
  • What I'm trying to ask is, is the parameter type of setBackerList an address[] memory?
    – Jesbus
    Commented Jun 23, 2018 at 10:22
  • good point, it was just declared as this function setBackerList(address[] newBackerList) public { ... } Commented Jun 23, 2018 at 10:29

2 Answers 2

13

Here's a way to do backerList.length--; on an address[] memory backerList by using inline assembly:

assembly { mstore(backerList, sub(mload(backerList), 1)) }

Some important points to remember:

  • Make sure this assembly code never runs when backerList.length == 0 (don't allow the array length to underflow)

  • Don't try to use this to increase the size of an array (by replacing sub with add)

  • Only use it on variables with a type like ...[] memory (for example, don't use it on a address[10] memory or address)

Disclaimer: The use of inline assembly is usually not recommended. Use it with caution and at your own risk :)

5
  • 1
    amazing and scary, how risky is it for me to use it? that would be a neat solution for me. Commented Jun 23, 2018 at 10:39
  • @RickChen I certainly recommend testing it thoroughly. The major concerns are: Don't use it on empty arrays. Only use it on variables with a type like ...[] memory.
    – Jesbus
    Commented Jun 23, 2018 at 10:43
  • Is there any update in 2022 or is this still the only way of doing this? Commented May 27, 2022 at 9:55
  • Why not use add to increase the size of the array? Seems like I've successfully used it to 'push' to a memory array. It's worked in testing at least. Thanks for this comment btw, that one line of Yul to 'pop' (and apparently push) to memory arrays has been a big help
    – Ryan Sea
    Commented Oct 29, 2022 at 23:37
  • 2
    @RyanSea You can imagine EVM memory to be a uint8[2**64-1]. When you run uint[] memory a = new uint()[10]; the compiler allocates part of that array to store a. The compiler may decide to use the memory directly after a for some other purpose (b) because it rightfully assumes that no language feature can grow a. If you use inline assembly to enlarge a then you will be overwriting b. If some other code writes to b, it will overwrite the extended part of a. Bad times. It may 'work' because there is no b, but it doesn't work because you've lost all safety guarantees.
    – Jesbus
    Commented Oct 30, 2022 at 19:13
1

Yes you are correct, you can't reduce size of memory array explicitly, it's only applicable for storage array. But you can use delete operator to clear memory, which will save your gas.

However the size of the array will not change, it will remain the same. You need to create extra variable to track size of array.

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.