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.
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.
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.