1

In some contexts, the keyword memory seems quite similar to a reference type in C++, where it gives an alias to a variable (see method 1 below). It confuses me when it's used to specify the return value data location.

I tested my code in Remix, supposedly both method 1 and 2 would return same values. However method 2 returns an array of all zeros. Could somebody tell me what's happening here?

// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.8;

contract Test3 {
    struct A {
        uint256 a;
        uint256 b;
    }
    
    // method 1: assigning values in the loop
    function LoopThrough() external pure returns (A[] memory _A) {
        _A =  new A[](5);
        for (uint256 i = 0; i< 5; ++i) {
            A memory _memoryA = _A[i];
            _memoryA.a = 123;
            _memoryA.b = 456;
        } 
    }

    // method 2: assigning value in another function
    function LoopThrough2() external pure returns (A[] memory _A) {
        _A =  new A[](5);
        for (uint256 i = 0; i< 5; ++i) {
            A memory _memoryA = _A[i];
            _memoryA = _internalReturn();
        } 
    }

    // helper function
    function _internalReturn() internal pure returns (A memory _a) {
        _a.a = 123;
        _a.b = 456;
    }
}

Edit 1

In C++, method 2 seems to be working. Here's a link to C++ code on Compiler Explorer.

1
  • The memory keyword only references where the data is stored.
    – Ismael
    Commented Oct 6, 2022 at 0:09

1 Answer 1

0

Let's call an instance of the struct A an 'object' for the purpose of this example I'm going to explain to you.

With this line:

A memory _memoryA = _A[i];

The variable _memoryA contains a reference to the 'object' in the array _A at index i. The _memoryA variable is not the object, it just has a reference to the object, and the object can be modified through it, doing what you are doing in your LoopThrough function, like _memoryA.a = 123;. That's fine, that works.

The problem of the LoopThrough2 function is that it does not modify the 'object' through the reference that the _memoryA variable has, it completely replaces the reference to the object at index _A[1] with the reference of a new A 'object' created and returned in the function _internalReturn(). So, the 'object' at index _A[1] is not be modified by this because it was not modified using the dot operator like aReference.property = value.

You could assign this new object to the index of the other object if you want, like:

function LoopThrough2() external pure returns (A[] memory _A) {
        _A =  new A[](5);
        for (uint256 i = 0; i< 5; ++i) {
            _A[i] = _internalReturn(); // Like this
        } 
}
1
  • Thanks Jeremy, but I don't understand it completely replaces the reference to the object ... with the reference of a new .... Since the left hand side is a reference, and the right hand side is the new object, shouldn't the new object be assigned to the reference, which is _A[i]? I updated my question with a C++ example to illustrate my idea.
    – Yongkin
    Commented Oct 6, 2022 at 10:45

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.