Ethereum Solidity: Memory vs Storage & How to initialize an array inside a struct

Georgios Konstantopoulos
Loom Network
Published in
3 min readFeb 13, 2018

--

In Loom Network’s Telegram (which has ~8,000 members!) people ask questions on various topics such as Loom’s roadmap, theoretical blockchain and Ethereum questions, and Solidity troubleshooting.

There was a specific question that was asked, which involved initializing an array inside a struct. The person who asked it then provided their code, wondering why it does not work. I could not think of an answer of the top of my head so I decided to talk about this topic briefly in a post.

The not-working code can be found below. I encourage you try finding a solution by yourself (you’ve been practicing on CryptoZombies all this time, haven’t you?).

Read on to find the answer.

Wrong Code

It should be noted that in the above fiddle, the keyword memory is needed when declaring the variable room. If it was declared as Room room, the compiler would return the following error:

TypeError: Type struct StructArrayInitWrong.Room memory is not implicitly convertible to expected type struct StructArrayInitWrong.Room storage pointer.

Some theory

A contract’s storage variables are the ones which define your contract’s state and are only changed by sendTransaction calls[1].

memory variables are temporary variables that exist only inside the calling function (they cannot be declared outside of one). They get wiped after the function exits and they are generally cheaper to use than storage variables — more details on gas costs here.

Let’s go through an example in order to understand how a storage variable can be used in a function in order to affect a contract’s state.

In the below fiddle, a copy of x gets passed in g() as and thus the state variable x will remain unmodified after execution (this is why we use the pure keyword.

On the other hand, y in h() is declared as storage, which means that x is passed by reference. As a result, the state variable x is modified after the call to h().

You can test the result by calling f() and then inspecting the value of y[2]. Even though g() is called after h(), it does not modify the state variable’s value.

Enough theorizing, let’s get to the answer to the initial question.

As we are unable to initialize the players array when initializing the structure, we are forced to do this in steps:

  1. Initialize the room structure to default values with an empty players array — as described here and in this fiddle.
  2. Push the room to the rooms array.
  3. Push msg.sender to the last room’s players array (rooms.length-1 always refers to the last element in an array).

Working Code Fiddle below:

getRoomPlayers added for debugging. Test succesful initialization with getRoomPlayers(0)

The trick here is that new address[](0) allocates memory for an empty array of addresses. After the initialization, the room gets added to rooms and is now part of a storage variable. This allows us to operate on the array players and push values to it.

Note: If we did a new uint[](8) we would get an array of 8 zeros. You can test it in this fiddle.

That’s all for today, hope we cleared some misunderstandings regarding storage/memory and how to use them in your functions. Let us know about your questions on our Telegram channel, and if they cannot be answered in a few messages we will dedicate a post on it (or maybe a CryptoZombies lesson!)

Loom Network is the multichain interop platform for scaling high-performance dapps — already live in production, audited, and battle-tested.

Deploy your dapp to Loom’s Basechain once and reach the widest possible user base across all major blockchains today.

New to Loom? Start here.

Want to stake your LOOM tokens and help secure Basechain? Find out how.

Like what we’re doing here? Stay in the loop by signing up for our private mailing list.

--

--