A guide to all the variable types in Solidity

In this tutorial, we are going to review and learn all the variable types in Solidity, and how and when to use them.

In this tutorial, we are going to review and learn all the variable types in Solidity, and how and when to use them.

Integers in Solidity

First off, we have signed and unsigned integer. The difference is that an unsigned integer cannot be negative whereas signed integers can be negative.

Unsigned integers are represented with uint and signed integers are represented by int.

However, the name of the type can use a suffix which is the bits that the number uses in memory.

So you have types int8 and uint8 up to uint256 and int256 with steps of 8.

If you only put uint or int  it's exactly like using uint256 and int256, respectively.

Unsigned integers are usually more used than signed integers. For numbers, the go-to type is usually uint256.

But you also have int256 if you want to use negative values.

Example:

uint256 myNumber = 123;

To sum up, usually the go-to type for integers is uint256 and if you want to support negative values it's int256.

Both sign and unsigned integers support basic operations: additions, subtractions, multiplications, divisions and modulo.

They also support basic comparisons with <, >, <=, >=, != and ==.

Lastly, with every of these integer types, you have shorthand syntaxes for operations like a = a + n. So you have +=, -=, *=, /=, %=.

To represent exponents, you can use ** so 10 to the power of 18 would be:
10 ** 18.

Booleans in Solidity

Booleans are represented with the bool keyword in Solidity and the only possible values are true or false.

The logic operators that booleans have are:

  • ! (logical negation)
  • && (logical conjunction, “and”)
  • || (logical disjunction, “or”)
  • == (equality)
  • != (inequality)

Addresses in Solidity

Solidity has a type to represent addresses instead of using strings: address.

There are 2 types of address types:

  • address: holds an address and has the byte size of an Ethereum address
  • address payable: Same as address, but you can send and receive ETH from and to it.

The reason why there is a distinction is that address payable is an address you can send Ether to while you're not sure if you can send ETH to a plain address, for example because it might be a smart contract that was not made to accept ETH.

To convert and address into a payable address to be able to send ETH to it, you can do: payable(<address>) (and replace <address> with the variable you want to convert).

Strings in Solidity

Strings in Solidity hold characters between double quotes or single quotes. They work like arrays but don't have the same operations.

Strings don't support index based access of the values inside. Also, strings don't have the .length property like arrays and they don't have all the other array functions like push or pop.

Also, Solidity doesn't have functions to easily manipulate strings although libraries exist for that.

However, you have the .concat() function to concatenate two string values.

Example:

string a = "A";
string b = "B";

string c = a.concat(b); // equals "AB"

Bytes in Solidity

In Solidity the bytes type represents a binary value. This type is used to store binary values. You have byte types from bytes1 to bytes32.

You won't use that type very often but it's important to know it exists to not be surprised when you see it.

You can use it to store anything in binary as long as it's under the size of the type. If you use bytes32, the value need to be less that or equal to 32B.

A few examples:

bytes32 a = "aaa"; // a string
bytes32 b = 0x01; // a binary value
bytes32 c = 1 // a number

The contract type in Solidity

When you create a contract in Solidity, you basically create a type. If you declare a contract A, you can instantiate it in another contract and use its functions.

If I create an instance of a smart contract called MyContract inside another smart contract and then check the type of that variable using the type function, it will return MyContract.

Enums in Solidity

Enums, or enumerables, in Solidity allow you to create your own type to represent choices, possible values for a variable or the state of something.

In the example below, I create a DeliveryStatus enum that represents the state of a delivery.

Enums can be declared outside of a smart contract, inside of it or in a separate file that you can import to use the enum.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

enum DeliveryStatus {
    Pending
    Accepted
    Rejected
    Cancelled
    Shipped
    Delivered
    FailedToDeliver
    Returned
}

contract Order {
    DeliveryStatus status;
    
    // Returns uint
    // Pending - 0
    // Accepted - 1
    // Rejected - 2
    // Cancelled - 3
    // Shipped - 4
    // Delivered - 5
    // FailedToDeliver - 6
    // Returned - 7
    function getStatus() public view returns (DeliveryStatus) {
        return status;
    }

    // Update status by passing uint into input
    function setStatus(DeliveryStatus _status) public {
        status = _status;
    }

    // You can update to a specific enum like this
    function cancelOrder() public {
        status = DeliveryStatus.Cancelled;
    }
}

The example above shows you how to create an enum and how to get and set the value of a variable that uses that enum type.

Note that when you get the value of a variable that uses an enum type, it will return you a uint containing the position of the value in the enum declaration, starting at 0.

In our case, if status is Pending, the getStatus function will return 0. If the value is Accepted, it's going to be 1 and so on.

To set a new value, you can either use a uint with the position of the value you want to set in the enum (like in setStatus) or you can use the enum and access the value you want directly (like in cancelOrder).

Structs in Solidity

Structs in Solidity allow you to create a new data type that you can use to store complex data.

For example, if you want to store a person's information, you'll probably need variables for the name, age, email, gender and other things. Creating variables for all the data you need to store would be repetitive and you would only be ably to store information about a single person.

To avoid that problem, you can create a struct.

It's important to have in mind that a struct cannot have a variable of its own type inside of itself, not even in nested objects.

Like enums, you can declare them outside or inside a smart contract or in their own file and import it.

struct Entry {
    address participant;
    string email;
}

contract Lottery {
    Entry[] public entries;
    
    function createEntry(string calldata _email) public {
        // 3 ways to initialize a struct
        
        entries.push(Entry(msg.sender, _email));
        
        // OR

        // entries.push(Entry({participant:msg.sender, email:_email}));
        
        // OR

        // Entry memory entry;
        // entry.participant = msg.sender;
        // entry.email = _email;
        // entries.push(entry);
    }

    // getting values
    function getEntry(uint _index) public view returns (string memory email, address participant) {
        Entry storage entry = entries[_index];
        return (entry.email, entry.participant);
    }

    // update a value
    function updateEmail(uint _index, string calldata _email) public {
        entries[_index].email = email;
    }
}

In the example above, you can see how to create a struct, how to create an instance of the struct and how to get and update a property of the struct (works like an object in other languages)

Arrays in Solidity

Arrays deserve an entire article because they need more explanations. You can find it here:

A full guide to Arrays in Solidity and the operations on arrays
In this guide we are going to learn everything about Arrays in Solidity and how to create arrays, add and remove elements from arrays in Solidity.

Mappings in Solidity

Finally, we have mappings. Mappings are basically like JSON. They are used to store any complex data with multiple properties in the format that you want, just like JSON.

To explain it differently, it's like an array but you can set the value you want in the indexes.

Here is an example:

contract MyToken {
    mapping(address => uint256) balances;
    
    function buyTokens(uint256 amount) public {
        // add an element to the mapping
        balances[msg.sender] = amount;
    }
    
    function sellTokens(uint256 amount) public {
        // get a value
        if (balances[msg.sender] >= amount) {
            // update value
            balances[msg.sender] = balances[msg.sender] - amount;
        }
    }
    
    function sellAllTokens() public {
        // completely remove a value
        delete balances[msg.sender];
    }
}

In the example above, you can see how to create a mapping, how to add a new value, how to delete a value how to get a value and how to update a value.

And that's it 🎉

Thank you for reading this article, if you want to get better at blockchain development, leave your email below and you'll get:

  • access to the private Discord of a community of Web3 builders
  • access to free guides that will teach you Blockchain Development