2

When I use the below contract in solidity.

struct Funder {
    address addr;
    uint amount;
}

contract FundContract
{
    struct Campaign {
        uint numFunders;
        mapping (uint => Funder) funders;
    }
    mapping (uint => Campaign) campaigns;
       
    function updatestruct(uint campaignID) public
    {
          Campaign storage c = campaigns[campaignID];
         
          c.funders[c.numFunders++] = Funder(msg.sender, 100);  //  How this is fine ?
          
          Funder storage f  = Funder(msg.sender, 100); // Why this is a compilation error
    }

}

As per the solidity documentation, the line

 c.funders[c.numFunders++] = Funder(msg.sender, 100);

creates a new temporary memory struct, initialized with the given values, and copies it over to local storage c.

Similarly, I tried the below line

Funder storage f  = Funder(msg.sender, 100);

I was expecting the same, however, I get the compilation error instead " Type struct Funder memory is not implicitly convertible to expected type struct Funder storage pointer."

Why is there a compilation error here, as I expected it to create a temp memory and copy it over to the local storage f like the previous one with local storage c?

Are some details available as to how solidity struct memory works in both cases?

2
  • I think this answer will be helpful: ethereum.stackexchange.com/questions/72307/…
    – Julissa DC
    Commented Oct 15, 2021 at 18:37
  • Thanks @JulissaDC, but nope I don't think it fits this category as maps in solidity have only storage. The link you shared does not have local storage and does not explain why temp memory was not created for local storage.
    – yk28
    Commented Oct 16, 2021 at 2:25

1 Answer 1

2

When you declare a mapping inside a struct, it can only be of type storage, you can't assign values to it in a temp memory, it just won't work. Here's a link that might help you: using mappings inside structs. When you create a struct Funder and assign it to your mapping funders at a specific index it works because you're accepting a struct of type Funder=>mapping (uint => Funder) funders;However, when you're trying to allocate a struct to a type storage, you have to explicitly do so. For ex:

c.numFunders++;
Funder storage f = c.funders[c.numFunders];
f.addr = msg.sender;
f.amount = 100;

The method you used is for the memory allocation. Here's another link that will explain the process. https://medium.com/loom-network/ethereum-solidity-memory-vs-storage-how-to-initialize-an-array-inside-a-struct-184baf6aa2eb. An array has been used in this example but it's based on the same principle.

7
  • Exactly, you initialize it and assign it to the specified index in the map.
    – Icarus23
    Commented Oct 16, 2021 at 12:54
  • Thanks, @icarus23. So what I understand is: In Solidity, for maps, as it has only storage type, it is possible to create a new temp memory, initialize it, and copy it over to storage if the map was part of a local storage variable (in this case Campaign storage c ). However, for the regular structs and arrays in local storage without maps, you cannot create temp memory and copy it to local storage. I don't get the idea as to why it was designed like this. For maps temp memory gets created and then copied to storage , while for structs and arrays this does not work.
    – yk28
    Commented Oct 16, 2021 at 12:57
  • I don't understand exactly what you mean by However, for the regular structs and arrays in local storage without maps, you cannot create temp memory and copy it to local storage. You can achieve the desired result with a regular struct: MemoryStruct memory structGig = MemoryStruct(param,param) and then copy it to the storage by creating an array MemoryStruct[] struct and pushing it into the array struct.push(structGig). Here's a link that explains the process better. medium.com/coinmonks/…
    – Icarus23
    Commented Oct 16, 2021 at 13:09
  • I can reorganize my sentence for easy understanding. The line, ``` c.funders[c.numFunders++] = Funder(msg.sender, 100); ``` assignment is for local storage map, Funder is first allocated in temp memory, initialised and then copied to local storage variable c.funders. For the line, ``` Funder storage f = Funder(msg.sender, 100); ``` which is a local storage struct, Funder cannot be allocated in temp memory, initialized and copied to local storage f. In this case, you need explicit storage assignment only.
    – yk28
    Commented Oct 16, 2021 at 13:20
  • 1
    Thanks @icarus23. I am not looking for anything specific, I am just trying to understand the solidity compiler behavior for maps, structs, and arrays. Now I get the behavior of the compiler. For maps (has only storage), temp memory is automatically created and copied to storage, while for structs and arrays in storage, compiler does not handle it, the user needs to do it explicitly as you said. (either assign to another storage variable or use memory and struct.push()).
    – yk28
    Commented Oct 16, 2021 at 13:57

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.