Solidity Bits— storage vs. memory

Alexander Lee
Coinmonks
Published in
3 min readJun 7, 2018

--

Photo Credit

Coding in Solidity is not always intuitive, but it’s fun. One of the small challenges I had to wrap my head around was the difference between storage vs. memory.

Imagine a simple example like the one below

pragma solidity ^0.4.22;contract Fruits {
string[] public items;
constructor () public {
items.push('apple');
items.push('orange');
}
}

If I was to deploy this contract, items at the 0 and 1 index would be ‘apple’ and ‘orange’ respectively. Easy enough.

What if I try to create a new array inside of my constructor function pointing to the itemsvariable array? Seems easy enough.

constructor () public {
...
string[] newItems = items;
}

But wait! we get a warning like the one below!

Understand the warning? I didn’t either.

To fully comprehend what is going on lets discuss how Solidity interprets memory vs. storage.

Storage vs. Memory

Solidity views the storage vs. memory relationship in 2 different ways.

  1. Contract state data

2. Variable value declaration

  • In this scenario, variable value declaration can be defined as storage or memory depending on how you want to save that variable (further explained below)

For our example purpose, items is a storage state inside of the Fruits contract. With the new variable newItems, we have two options, save the variable in memory or storage. I will review both options below.

NewItems as storage

If newItems was saved as a storage, you have to include the keyword storage before newItems. Example shown below.

string[] storage newItems = items;

By adding the storage value the warning should disappear. But what exactly is this doing? By adding storage , newItems now POINTS to the items array. In other words, any changes you make to newItems , will directly affect the items array.

pragma solidity ^0.4.17;contract Fruits {
string[] public items;
constructor () public {
items.push('apple');
items.push('orange');
string[] storage newItems = items;
newItems[1] = 'lemon';
}
}
// items[1] will now be lemon
// items[0] will remain the same as 'apple'

In conclusion, the storage key forces the newly created variable to point to the state variable (items) and not a copy. Any changes made to the new variable will directly change the structure of the contract state variable.

NewItems as memory

newItems has an alternative method to persistence. Instead of storage , there is a memory option. The memory option functions as a copy as opposed to a pointer. Thus, using the memory key and making mutations on the newly created variable WILL NOT affect the original state variable. Example below.

pragma solidity ^0.4.17;contract Fruits {
string[] public items;
constructor () public {
items.push('apple');
items.push('orange');
string[] memory newItems = items;
newItems[1] = 'lemon'
}
}
// items[1] will remain the same as 'orange'
// items[0] will remain the same as 'apple'

Conclusion

I hope this resolves any question regarding this warning regarding memory vs. storage. I view storage (state) as a hard drive and memory (local variables, temporary) as RAM. If you anticipate on creating functions that make state changes, storage might be the best option. If you need a copy of the data but not necessarily want to manipulate the contract state use memory.

Side Note

Any value passed into a Contract function will be sent via memory (default). A function that takes that parameter will not manipulate the contract state. Example below.

pragma solidity ^0.4.17;contract Fruits {
string[] public items;
constructor () public {
items.push('apple');
items.push('orange');

changeFirstElement(items);
}

function changeFirstElement(string[] newItems) pure private {
newItems[0] = 'lemon';
}
}
// items[1] will remain the same as 'orange'
// items[0] will remain the same as 'apple'

If you need to enforce state change, you can add the storage key in the parameter.

function changeFirstElement(string[] storage newItems) private {
newItems[0] = 'lemon';
}

fin

--

--