1

While working on my most recent project, I realized that since I've learned Solidity, I have been modifying structs in a mapping like so:

mapping(uint256 => Person) map;
...
map[id].name = _name;
map[id].age = _age;
etc...

I'm wondering now though whether the more correct way would be like so:

mapping(uint256 => Person) map;
...
Person storage it = map[id];
it.name = _name;
it.age = _age;
etc...

If the first method is constantly hashing and looking up "it" in the mapping, then I would think that the second is superior. If the compiler optimizes it all away anyway, I would think the first would be preferred as it lessons the risk of someone mistakenly not assigning the storage struct to anything. Then we would have the feature (which I think should be a bug) where a struct in storage left unassigned points to the contract and not to the struct it should have been assigned to.

For my analysis of the second method, I am also assuming that creating the variable "it" is negligible or free as it's just a pointer to something in storage and not a struct declared in memory. If I'm wrong here, please help correct any of my misinterpretations! Thank you!

1

Yes, second option is cheaper.

In the first case, you have to hash everytime you want to write, load from storage , write to storage.

You can do the math with this, butcould be not up-to-date.

In the second case, I believe you hash once, load from storage once and still write thrice. Not sure about the loading once part but in any case, still cheaper than the first case.

And obviously, to be sure and prove it, we test it, which I did. :)

contract Test {

  struct Node{
    uint x;
    uint linked; //index to next
    bool nil;
  }

  mapping (uint => Node) nodes;

  function Test(){
      nodes[0] = Node(59,1,false);
  }

  function test1(){
      nodes[0].x = 6;
      nodes[0].linked = 2;
      nodes[0].nil = true;
  }

  function test2(){
      Node storage node = nodes[0];
      node.x = 6;
      node.linked = 2;
      node.nil = true;
  }
}

Hold and behold! test1() used 51969 gas while test2() used 36804 gas.

  • There's an extra indexing penalty on the first read of a variable I think, if you run it again you'll see test1 is cheaper the second time around. (still 22 gas more expensive than test2 though). Not sure why I've never seen mention of this extra 15k gas thing but it only seems to happen the first read. – norganna Apr 1 '18 at 17:23
  • You are probably right but can't find official documetation about it. – Eli Drion Apr 1 '18 at 17:28
  • 1
    Appreciate the answer and the great discussion. This 15K is a huge difference in the scope of this question. The 22 gas probably builds up based on what's being stored and how much of it there is, but it's not as large of a difference as it initially looks. – Matthew Ludwig Apr 1 '18 at 19:58
  • Will definitely be using the better option in the future for correctness. With this as the accepted answer, it feels important that solidity get a warning for this in the future. I've heard mention of it previously and am hopeful to see it soon. – Matthew Ludwig Apr 1 '18 at 19:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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