The Solidity data types can be classified according to the data location. If variable store its own data; it is a value type. If it holds a location of the data; it is a reference type. We have gone through value types in previous articles. So, in this article, we will learn about reference types.
As discussed, reference types do not store the data directly to the variable, instead, it stores the location of the data. With a reference type, two different variables can reference the same location, in such a case; any change in one variable will affect to another variable; therefore value types need to be handled very carefully.
Since the version 0.5.0 of Solidity, for all complex types, you need to define data location explicitly with a variable.
Reference types consist of,
- Arrays
- Structs
- Mapping
Learn more about data location in detail: Data Locations In Solidity
Arrays
Arrays are the groups of variables of the same type in which each individual variable has a particular location called index. By using that index location, you can access that variable. The size of arrays can be fixed size or dynamic.
Fixed Size Arrays
Fixed size arrays have pre-defined size while declaration. For example, an array of fixed size 5 and element type uint is written as,
- uint[5] arrayName;
- uint[5] marks = [uint(50), 60,70,80,90];
- pragma solidity ^0.5.0;
- contract Types {
- function getMarks() public pure returns (uint[5] memory){
- uint[5] memory marks = [uint(50), 60, 70, 80, 90];
- return marks;
- }
- }
- //result
- //50,60,70,80,90
In the example above, the type of [50, 60, 70, 80, 90] is uint8[5] memory. Because the type of each individual value is uint8; if you want the result in uint[5] memory, you need to convert the first element to uint.
Or you can declare an array as a state variable and initialize in a function
- pragma solidity ^0.5.0;
- contract Types {
- uint[5] marks;
- function getMarks() public returns (uint[5]memory){
- marks = [uint(50), 60,70,80,90];
- return marks;
- }
- }
- //result
- //50,60,70,80,90
Dynamic Arrays
Dynamic arrays don't have predefined size at the time of declaration; the size then will be determined at a run time.
Declaration
- uint[] arrayName;
- uint[5] mathMarks = [uint(50), 60,70,80,90];
- int[] scienceMarks = new int[](5);
- pragma solidity ^0.5.0;
- contract Types {
- uint[] mathMarks = [10, 20, 30, 40, 50]; //inline
- uint[] scienceMarks;
- function getMarks() public returns(uint[] memory, uint[] memory){
- scienceMarks = [60, 70, 80, 90, 100]; // inline
- return (mathMarks, scienceMarks);
- }
- }
- //result
- //"0": "uint256[]: 10,20,30,40,50",
- //"1": "uint256[]: 60,70,80,90,100"
- pragma solidity ^0.5.0;
- contract Types {
- uint[] scienceMarks;
- function getMarks() public returns (uint[]memory){
- scienceMarks = new uint[](5); // using new keyword
- scienceMarks[0] = 10;
- scienceMarks[1] = 20;
- scienceMarks[2] = 30;
- scienceMarks[3] = 40;
- scienceMarks[4] = 50;
- return (scienceMarks);
- }
- }
- //result
- //"0": "uint256[]: 10,20,30,40,50"
- pragma solidity ^0.5.0;
- contract Types {
- function getMarks() public returns(uint[] memory) {
- uint[] memory scienceMarks = [uint(60), 70, 80, 90, 100]; // error
- return scienceMarks;
- }
- }
Array Members
length
Length member is used to getting a count of elements that array contains. The size of a memory array is fixed once they are created, but the length of dynamic-sized arrays can be defined at runtime; in this case length member is used to resize the array with the storage location.
- pragma solidity ^0.5.0;
- contract Types {
- uint[] array;
- //passing _length = 3
- function getLength(uint _length) public returns(uint) {
- array.length = _length;
- return array.length; // return 3
- }
- }
Dynamic storage arrays have a member called push; that is used to add an element to the array at the last position.
- pragma solidity ^0.5.0;
- contract Types {
- //storage variable
- uint[] arr;
- function insert() public returns(uint[] memory) {
- arr = [1, 2, 3];
- //pushing values to the array
- arr.push(4);
- arr.push(5);
- arr.push(6);
- return arr; // return 1,2,3,4,5,6
- }
- }
Dynamic storage arrays have a member called pop that you can use to remove the last element from the array.
- pragma solidity ^0.5.0;
- contract Types {
- uint[] array;
- function removeLastOne() public returns(uint[] memory) {
- array = [1, 2, 3];
- array.pop();
- return array; // return 1,2
- }
- }
Special Arrays
In Solidity, bytes and string are special arrays.
Bytes array
The bytes array has dynamic size and is declared using "bytes" keyword; or it can be initialized in function as follows:
- pragma solidity ^0.5.0;
- contract Types {
- bytes byteArray1 = new bytes(5);
- bytes byteArray2;
- function initializeByteArray() public{
- byteArray2 = new bytes(5);
- }
- }
- pragma solidity ^0.5.0;
- contract Types {
- bytes byteArray2;
- function assignValue() public{
- byteArray2 = "C# Corner";
- }
- function getValue() public view returns (bytes memory){
- return byteArray2;
- }
- }
- pragma solidity ^0.5.0;
- contract Types {
- bytes byteArray2;
- function assignValue() public{
- byteArray2 = "C# Corner";
- byteArray2.push('-');
- byteArray2.pop();
- }
- function getLength() public view returns (uint){
- return byteArray2.length;
- }
- }
String is also a dynamic array just like bytes, but with special constraints. Unlike other arrays, string doesn't have the index, thus string doesn't contain array members -- length, push and pop.
Example
- pragma solidity ^0.5.0;
- contract Types {
- string firstName;
- function assignValue() public returns (string memory, string memory){
- firstName = "C#";
- string memory secondName = "Corner";
- return (firstName, secondName);
- }
- }
Structs
Solidity enables users to create their own type in the form of Structure. The structure is the group of different types although it is not possible to contain a member of its own type. Structure is a reference type variable and can contain both - value types and reference types.
Declaration
- struct <name of structure> {
- <type> variable1;
- <type> variable2;
- pragma solidity ^0.5.0;
- contract Types {
- struct User {
- string name;
- uint age;
- bool isValid;
- }
- User _user = User("John", 40, true);
- function getUserInfo()
- public view
- returns (string memory, uint,bool) {
- return(_user.name, _user.age, _user.isValid);
- }
- }
- //result
- //John, 40, true
Mapping Types
Mapping types are the most used reference type; they are used to store data in a key-value pair; where the key can be any built-in value types or byte and string. You can think of it as a hash table or dictionary as in any other language, in which a user can store data in a key-value format and data can be retrieved by key.
Declaration
- mapping(_KeyType => _ValueType) <access specifier> <name>;
- mapping (address => uint) account;
Example of storing and retrieving user information using mapping:
- pragma solidity ^0.5.0;
- contract MappingExample {
- mapping(address => uint) account;
- function updateBalance(uint newBalance) public {
- account[msg.sender] = newBalance;
- }
- function getBalance(address _address)
- public view returns (uint) {
- return account[_address];
- }
- }

The first method is for saving the balance as value and the address of the user as a key, and in the second method we're retrieving the value of the balance we stored on address key. Let's run it and see the output.

And we're able to see the value that we've stored in mapping!
In this article, we have discussed different reference types - arrays, structures, mappings. We’ve also covered the usage of all. In our next article, we will learn constructor in Solidity.
Reference
- https://solidity.readthedocs.io/en/v0.5.0/

Join the conversation! Your thoughts help the community grow.