This is the second Aventus technical blog on Solidity from Alex Pinto, a recent addition to our blockchain engineering team. You can read his first post on . Working with Strings in Solidity There are many occasions when we want to pass to a function a group of similar data that may, or may not, be limited in number. The most basic data type for this situation is an array (and in several cases, this can be used to implement more advanced data structures). We can pass and return arrays without problems, as the following illustrates. The above uses arrays of , which represents a 256-bit integer, of unlimited size. That means I can pass any array of the correct type into the function. It also means I have to initialise the return array in before I can use it, since at the time is declared it does not allocate any memory for its elements (it could have any size). uint getArrayMultipliedByScalar outArray_ For comparison; if I used fixed-size arrays, as below, two things happen: I no longer need to initialise the outgoing array. The compiler returns an error if the function receives an array with any other size but 3. We can make arrays of other types, like and - but what about multi-dimensional arrays? bool address We can pass bi-dimensional arrays of fixed size: Sadly, things are more difficult with dynamic arrays. Some languages, like BASIC and Pascal, index bi-dimensional arrays by a tuple of indices. In these languages, arrays are genuine (rectangular) matrices. But in C-derived languages, multi-dimensional arrays are arrays-of-arrays, instead of matrices. That is the case with Solidity as well, and it pays to take some time to understand what this type declaration means: should be read as , that is, 4 arrays each of size 2. uint[2][4] (uint[2])[4] This is important when we consider dynamic arrays. We could have both of these kinds: The first example above is a fixed-size array which has 3 elements, each of which is a dynamic array. In the second case, we have a dynamic array outright, but its elements are arrays of fixed size. I discuss below how to initialise , which is the most interesting case of the two. Regarding , because it is a dynamic array, we first must allocate memory for it using and then we can access the fixed-size elements. The example below works: fixedSizeArray dynamicArray new Initialisation of multi-dimensional dynamic arrays Let’s explore an example similar to the above in more detail: TypeError: Type uint256[3] memory is not implicitly convertible to expected type uint256[3] storage pointer. The arrays and are declared as state variables of the contract, and so are by necessity storage references. arrays can not be initialised from expressions, as these are of type . Nevertheless, we can initialise each of the arrays inside using memory-array expressions, as shown above. fixedSizeArray dynamicArray Storage new memory fixedSizeArray For comparison, I included also two cases where I try to assign a memory array to an explicit storage one. In the constructor, this works, but not in the second function. Why? This is because the types of and of are not exactly the same. The former is a state variable of the contract, and when it is referred inside the constructor, its type is (to see this, change the assignment’s right value to something illegal, such as 7, and the error message will show you the types involved). In comparison, the type of is . Subtle difference. In the first case, we have a reference to a location in storage, and the assignment copies the memory array to that storage. In the second case, we try to assign to a local variable which according to the just creates a new reference to a previous pointer: storageArray localStorageArray uint256[3] _storage ref_ localStorageArray uint256[3] _storage pointer_ documentation Assignments to local storage variables only assign a reference though, and this reference always points to the state variable even if the latter is changed in the meantime. Excerpt from Solidity documentation In the above example, is a pointer to the same location known as , and modifying one causes changes in the other. But in our case, we are trying to assign a memory array to a storage variable which, being of a different type, cannot produce a pointer to that memory location. y x On the other hand, when we initialise , we are actually referring to a storage reference. In this case we can assign from a memory array, which has the effect of completely copying the source over the target, erasing all of its previous contents. fixedSizeArray Can we pass multi-dimensional arrays to functions? It depends! We can use Solidity’s polymorphism to write four functions with the same name, and different signatures, exploring all combinations of dynamic and fixed-size bi-dimensional arrays. Two of these functions are illegal, only because their particular array type cannot be passed to a function. Illegal is a bit of a strong word: the error says the type can be used, but only with the new experimental ABI encoder; and that in order to use it, it is necessary to include . However, we then would get a warning saying that it should not be used in production code. pragma experimental ABIEncoderV2; This restriction will likely be waived in the future, as new versions of Solidity come along, but for now, I just won’t use these features and will look for workarounds. The common feature between these two types is that of the array — that is the type of its elements — is dynamic, of unknown size. These types cannot be passed into nor returned from a function. the inner type I will finalise this post with another example: The last two functions are illegal. The reason why is very consistent with everything that has been said before: and are dynamic types. Specifically, they are respectively, of UTF-8 characters, and of bytes. For that reason, the above return types are not really simple uni-dimensional arrays like those of and , but are instead bi-dimensional arrays with a dynamic inner type. And because of that, they cannot be passed into nor returned from functions at the current stage of Solidity. string bytes arrays: getInts getAddresses About the Author Alex is a software engineer at Aventus, working on the blockchain engineering team. He has 20 years of experience working in technology, completing a PhD in Computer Science as well as a post-doctorate in Cryptography. As part of his research, Alex on Kolmogorov Complexity, Cryptography, Database Anonymization and Code Obfuscation. has published papers Alex also spent seven years lecturing at the University Institute of Maia, including directing the degree programmes for BSc Computer Science and Information Systems and Software.