Solidity Programming: Understanding Booleans and Integers

In previous blockchain programming articles, we introduced how to write our first smart contract with Solidity using the Remix IDE.

We also looked at how we can write data to the blockchain after the smart contract has been deployed.

In this series of articles, we will move on to a more practical blockchain programming project and create a "blockchain messenger". The goal of this smart contract is simple:

...to save a message on the blockchain that is readable to anyone and writable only to the person that deployed the contract.

We will also count how many times the message was updated.

To start, in this article we'll discuss two key data types in Solidity: booleans and integers. This article is based on notes from this Blockchain Developer course and is organized as follows:

  • Booleans with Solidity
  • Signed & Unsigned Integers with Solidity
  • Integer Rollover with SafeMath

Stay up to date with AI

We're an independent group of machine learning engineers, quantitative analysts, and quantum computing enthusiasts. Subscribe to our newsletter and never miss our articles, latest news, etc.

Great! Check your inbox and click the link.
Sorry, something went wrong. Please try again.

Booleans with Solidity

Booleans are one of the most fundamental value types in programming.

Booleans have either a true or false value and are defined as bool in Solidity.

To start, we'll create a new file in Remix called exampleBoolean.sol and start the contract with our SPDX license and pragma line as usual.

We'll then start the contract and add a bool called myBool:

//SPDX-License-Identifier: MIT
pragma solidity 0.8.14;

contract ExampleBoolean {
    bool myBool;
    
}

Here we can see the contract is compiling, but we can't do anything with it because we have no function and there's no interface to interact with the smart contract.

If we make this public and compile and deploy it, we see we have a button called myBool, which returns false:

The reason that it's not erroring out like other programming languages as it has a default value of false.

Let's now add a setter function called setMyBool that stages an argument bool and we'll call it the same name with an underscore. We'll also set it to be public and set myBool to _myBool to override that variable:

contract ExampleBoolean {
    bool public myBool;

    function setMyBool(bool _myBool) public {
        myBool = _myBool;
    }

}

If we deploy this again we now have a setter function and getter function and can set myBool to true:

We can also do logical negation with booleans, which means if we add ! before _myBool it will return false if we set true, and true if we add false.

contract ExampleBoolean {
    bool public myBool;

    function setMyBool(bool _myBool) public {
        myBool = !_myBool;
    }

}

Stay up to date with AI

We're an independent group of machine learning engineers, quantitative analysts, and quantum computing enthusiasts. Subscribe to our newsletter and never miss our articles, latest news, etc.

Great! Check your inbox and click the link.
Sorry, something went wrong. Please try again.

Signed & Unsigned Integers with Solidity

The next key value type to understand with Solidity programming are signed and unsigned integers.

Signed and unsigned integers are full numbers, meaning they have no decimal places. The difference between signed and unsigned integers is that signed integers can be negative and unsigned integers can only range from zero to a very large number.

How large can unsigned integers go exactly?

Unsigned integers can be between 0 and $2^{256} - 1$.

To understand the specifics of integers with Solidity, let's create a new file in Remix called ExampleUint.sol and a new contract called the same.

We will then define an integer called myUint and make it public so that we have a getter function.

//SPDX-License-Identifier: MIT
pragma solidity 0.8.14;

contract ExampleUint {
    uint public myUint;
    
}

If we deploy this we see we have a default value of 0 or we can initialize it with some specific value.

Let's now write a setter function called setMyUint() as follows so that we can update the integer value:

contract ExampleUint {
    uint public myUint;

    function setMyUint(uint _myUint) public {
        myUint = _myUint;
    }

}

As you can see uInt is actually an alias for uInt256, which is the size of the unsigned integer variable. This means the unsigned integer can store between 0 and $2^{256} - 1$.

We can also have smaller unsigned integers such as uint8, uint16, uint32, uint64 and so on if you want to save on storage or gas costs.

If we use uint8, however, and create a function to increment myUint by 1 and set the initial value to 250, after we increment five times we will get an error that it can only go to 255:

contract ExampleUint {
    uint256 public myUint;

    uint8 public myUint8 = 250;

    function setMyUint(uint _myUint) public {
        myUint = _myUint;
    }

    function incrementUint8() public {
        myUint8++;
    }
 
}

Finally, let's define a signed integer int and set it to -10 and then create a function to see that we can increment it over 0.

With signed integers, we can go from $-2^{128}$ to $2^{128} - 1$.

contract ExampleUint {
    uint256 public myUint;

    uint8 public myUint8 = 250;

    int public myInt = -10; 

    function setMyUint(uint _myUint) public {
        myUint = _myUint;
    }

    function incrementUint8() public {
        myUint8++;
    }

    function incrementInt() public {
        myInt++;
    }
 
}

Integer Rollover with SafeMath

In this section, we'll discuss a concept that is important to Solidity versions prior to 0.80.

Prior to Solidity version 0.80, arithmetic operations would always wrap in the case of an under of overflow.

There are a number of different libraries that introduce different checks for this, one of which is SafeMath. So in this section, we'll look at how this wrap works and what changed in Solidity version 0.8+.

To start, let's create a new contract in Remix called ExampleWrapAround.sol and we'll copy the code over from ExampleUint.sol.

We'll then change the contract name to ExampleWrapAround and remove the code relating to the integer as we won't need it.

Next we'll add a function to decrement our unsigned integer by one as follows:

//SPDX-License-Identifier: MIT
pragma solidity 0.8.14;

contract ExampleWrapAround {
    uint256 public myUint;

    uint8 public myUint8 = 250;

    function setMyUint(uint _myUint) public {
        myUint = _myUint;
    }

    function decrementUint() public {
        myUint--;
    }

    function incrementUint8() public {
        myUint8++;
    }
 
}

If we try and decrement our unsigned integer it will give an error as the default value is 0 and it can't go negative.

If, however, we change our Solidity version to pragma solidity 0.7.5 and use our decrement function again...we see that it doesn't give an error and our unsigned integer is very large:

In version 0.8+, Solidity changed this from an unchecked arithmetic operation to a checked arithmetic operation.

This means that after compilation there will be an additional check inside the byte code to ensure the decrement and increment arithmetic operations are not rolling over the integer or unsigned integer.

In order to get this unchecked behavior back in versions 0.8+, you have to wrap it in an unchecked block as follows:

function decrementUint() public {
        unchecked{ 
            myUint--;
        }
    }

So if we change our Solidity version back to pragma solidity 0.8.14 with this unchecked block, we see we get the same large number.

If you are using versions prior to 0.8, SafeMath provides functions to require added overflow checks, although if not it is provided natively in Solidity 0.8+ now.

Summary: Booleans and Integers with Solidity

To summarize booleans and integers with Solidity:

  • Booleans have either a true or false value and are defined as bool in Solidity.
  • Signed and unsigned integers are full numbers, meaning they have no decimal places.
  • The difference between signed and unsigned integers is that signed integers can be negative and unsigned integers can only range from zero to a very large number.
  • Prior to Solidity version 0.80, arithmetic operations would always wrap in the case of an under of overflow.
  • In version 0.8+, Solidity changed this from an unchecked arithmetic operation to a checked arithmetic operation.

In the next Solidity programming articles, we'll review more key data types including strings and bytes, address types, and more.