Solidity offers more data types than most programming languages. We can divide these types into value types and reference types. Value types are those which take on a particular value, while reference types store the reference to an object.
This programming tutorial will explore the built in types of the Solidity language while also contrasting them with the other popular languages so that you can easily see the differences.
Read: How to Manage Variable and Function Visibility in Solidity
Integer Types in Solidity
There are two types of available integer values in Solidity: signed and unsigned. The signed values lie on either side of the number line (i.e. they can either be positive or negative). The unsigned values begin from zero to the maximum accepted positive value.
Signed values can be of the following subtypes: int8, int16, int24, and int256. Similarly, unsigned values can be of the subtypes uint8, uint16, uint24, and uinit256. The shorthand for uint256 and unit are for int256 and int.
Astute developers may have noticed that integer types change by ranges of 8.
The maximum value that each integer type can accept is what differentiates the various types. For example, uint8 accepts a max value of 2**8 -1, uint16 a max of 2**16 – 1, and so on, to a maximum value of 2**256 – 1.
Address Types in Solidity
Ethereum has 20 byte (160 bit) hexadecimal values called addresses that it uses to identify accounts or smart contracts. Addresses are special numbers that must be declared using one of the following keywords: address or address payable.
The difference between the two keywords is that address payable can receive tokens while address cannot. Smart contracts normally use address, while user accounts use address payable.
It is possible for developers to convert a variable declared address to one which is payable using the payable() function, as shown in the following code example:
address a = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address payable b = payable (a);
Given the special nature of address types, Solidity provides a few useful methods and variables to get various information about their state. These include:
- Variables: address.balance is how much a given address has in the currency smallest units of the token. For Ethereum, this is Wei.
- Methods: address.send() sends tokens to an address and returns a boolean value. address.transfer() transfers tokens to an address and returns an error if false.
Read: Guide to Inheritance in Solidity
Solidity Functions
In Solidity, functions are types, unlike in many other programming languages. To create a function in Solidity, developers use the keyword function, followed by the function name and parentheses. The parentheses can optionally have arguments. These arguments are declared in the same manner as variables. Here is a code example showing how to create a basic function in Solidity:
function chooseWinner( address x) { // some code }
As you may have noticed in the code example above, our function also has curly brackets { }. This is where you place the method body. These { } can be used when you are defining an interface or an abstract method.
Solidity Reference Types
There are three reference types in Solidity: arrays, structs, and mappings. Whenever a programmer defines a reference type, they need to indicate its data location as well. The possible data locations include:
- storage: This consists of data that is permanently stored on the blockchain and for this reason it carries a high gas cost. All the state variables of a smart contract are stored here by default.
- memory: This is a temporary data location that lasts only until an external function call is made. This is where function parameters are normally stored. memory carries a low gas cost.
- calldata: This is a read-only memory location that stores function arguments. Developers cannot modify the data stored here in the function body.
Arrays
In Solidity, developers can declare an array in a similar manner to many other programming languages, such as Java. Here is how you declare an array in Solidity:
int48[12] width;
The above array, named width, can store 12 values of type int48. If you want to create a dynamic array, then do not place any value in the square brackets.
Unlike many other languages, where uninitialized values are treated as undefined, Solidity defines default values for each uninitialized array element. Developers can access an array element using its index position or place in the array. Index positions run from 0 to n-1, just like in other programming languages. Here is a list of Solidity array types and their default values:
- bool: false
- Integer: 0
- address: 0x0000000000000000000000000000000000000000
In addition, Solidity has some useful methods that can help programmers manipulate arrays, including:
- push(element): Used to add an array element to end of an array
- pop(): This removes the last element of the array and decreases the array length by 1
If you want to determine the length of an array, you can use the array.length field.
Structs
In Solidity, a struct is a data structure that can store elements of different data types. Here is an example of how to define a struct in Solidity:
struct EthereumTestnet{ int32 chainID = 5; address ensAddress = “0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e” }
To access a struct value, simply use the struct name followed by .element. For instance, to access the chain ID of the above struct you would use the following code:
int32 var = EthereumTestnet.chainID;
Mappings
A mapping stores data of key-value pairs. Any of the primitive data types in Solidity can be a key-value, except an object. Meanwhile, a value can be of any acceptable type.
To define a mapping in Solidity, developers use the keyword mapping, followed by the (key => value) and its name, as show in this code example:<//p>
mapping(address => uint256) public payments; // you can also add a visibility modifier as shown
The above mapping associates an address to however many tokens it paid. Programmers can access the value of a mapping by using the key of the desired value. You can also assign a value to it in a similar way. This concept is demonstrated in the code below, where we create a function to map an address and then returns the payment address. The comments break each section down in greater detail:
function subscribe() external payable { // sets value of mapping address sender = msg.sender; uint amount = msg.value; payments[sender] = amount; } function getPaidAmount(address addr) public view returns (uint){ // gets value for given address return payments[addr]; }
Final Thoughts on Solidity Data Types
In this programming tutorial, we learned how to work with various primitive data types in the Solidity programming language. Remember, whenever you are using a reference type, you always need to indicate its data location. For state variables, the data location is implicitly defined as storage, so you do not have to indicate it.