Solidity is a high-level, object-oriented programming language that is used to write smart contracts and build DApps. It also supports inheritance, libraries, and sophisticated user-defined types.
Solidity is statically typed, so the data type for each variable must be specified at compile time. The variables can only accept the data type for which they were designed by the developer and cannot be altered dynamically.
The differences between data types in Solidity and those of other programming languages are subtle, but significant enough that many developers find this topic to be confusing.
Like other programming languages, Solidity classifies data into different types. But, Solidity is somewhat unique in that it has several elementary types that can be combined to form complex types.
This article is designed to be a comprehensive guide to Solidity data types — both value types and reference types. Having a clear understanding of data types in Solidity is essential for building smart contacts.
Jump ahead:
A value type stores its data directly in the memory it owns. Variables of this type are duplicated whenever they appear in functions or assignments. A value type will maintain an independent copy of any duplicated variables. Therefore, a change in the value of a duplicated variable will not affect the original variable.
There are several value types in Solidity: signed integers, unsigned integers, Boolean, addresses, enums, and bytes.
A signed integer, declared with the int
keyword, is a value data type that can be used to store either positive or negative values in smart contracts.
int
is an abbreviation for int256, which has a range of -2 ** 255
to 2 ** 255 - 1
. This value type takes up to 32B by default, but we can make it smaller by specifying the number of bits in steps of 8. For example: int8
, int16
, int32
, etc.
Here’s an example of a signed integer in Solidity:
pragma solidity ^0.5.10 // example of int value type in solidity contract SampleInts } { int = -168; }
An unsigned integer, declared with the uint
keyword, is a value data type that must be non-negative; that is, its value is greater than or equal to zero.
uint
is an abbreviation for uint256. Just like signed integers, this value data type takes up to 32B by default. Again, we can make it smaller by specifying the number of bits in steps of 8. For example: uint8
, uint16
, uint32
, etc.
These integers are restricted to a range based on their size. For example, uint8
has a range of 0
to 2 ** 8 -1
, and uint256
has a range of 0
to 2 **256 - 1
.
Here’s an example of an unsigned integer in Solidity:
pragma solidity ^0.5.10 // example of uint value type in solidity Contract SampleUints } uint public u16 = 1890; uint public myUint u = 256; }
The bool
value data type is used in Solidity to illustrate cases that have binary results. A bool
has two fixed values: true
or false
, with false
being the default. This data type only takes up 1B of storage.
Solidity supports all standard Boolean operators, such as:
!=
(inequality)==
(equality)!
(logical negation)&&
(logical conjunction, “AND”)||
(logical disjunction, “OR”)It is essential to understand that you cannot translate the bool
data type into integers in Solidity like you would with other programming languages. Also, in Solidity any assignments to other Boolean variables creates a new copy of the variable.
Here’s an example showing how a bool
data type is declared and assigned a value in Solidity:
pragma solidity ^0.5.10 // example of a bool value type in solidity Contract SampleBool } bool public IsVerified = False; bool public IsSent = True; }
These variables can be modified and applied in both incoming and outgoing parameters within smart contracts.
An address value type is specifically designed to hold up to 20B, or 160 bits, which is the size of an Ethereum address.
Solidity actually offers two address value types: address
and address payable
. The difference between the two is that address payable
can send
and transfer
Ether.
We can use an address
to acquire a balance using the .balance
method and to transfer a balance using the .transfer
method.
Here’s an example of an address data type in Solidity:
pragma solidity ^0.5.10 // example of an address value type in solidity Contract SampleAddress } address public myAddress = 0xb794f5ea0ba39494ce839613fffba74279579268; }
Enums, or enumeration, values in Solidity consist of user-defined data types. This data type is used explicitly for constant values, such as the names of integral constants, making a smart contract easier to read and maintain. Enums can help reduce the incidence of bugs in your code.
Enums limit a variable to a few predefined values and each copy maintains its value.
Options are represented by integer values beginning with zero; you can also specify a default value for the enum.
Here’s an example declaring an enum
named food_classes
consisting of six constant values: carb
, protein
, fats-oils
, water
, vitamin
, and minerals
:
pragma solidity ^0.5.10 // example of an enum value type in solidity Contract SampleEnum } enum < food_classes > } carb, protein, fats-oils, water, vitamin, and minerals; }
It’s important to note that DApps do not recognize an enum
within a smart contract. An integer value that corresponds to the enum
constant must be provided.
In Solidity, byte refers to 8-bit signed integers. Everything in memory is stored in bits with binary values 0 and 1.
The bytes value type in Solidity is a dynamically sized byte array. It is provided for storing information in binary format. Since the array is dynamic, its length can grow or shrink.
To reflect this, Solidity provides a wide range — from bytes1
to bytes32
. The data type bytes1
represents one byte, while bytes32
represents 32B. 0 x 00
is the default value for byte. This value is used to prepare the default value.
Here are some examples of the bytes
data type in Solidity:
pragma solidity ^0.5.10 // example of a byte data type in hexadecimal format in solidity Contract SampleByte } bytes1 uu = 0 x 45; }
pragma solidity ^0.5.10 // example of a byte data type in integer values decimal format in solidity Contract SampleByte } bytes1 pp = 12; }
pragma solidity ^0.5.10 // example of a byte data type in -ve int values in decimal format in solidity Contract SampleByte } bytes1 ff = -62; }
pragma solidity ^0.5.10 // example of a byte data type in character values in solidity Contract SampleByte } bytes1 ee = 'd' }
Solidity reference types differ from value types in that they do not store values directly on their own. Instead, reference types store (or “reference”) the address of the data’s location and do not directly share the data.
Reference data types must be handled cautiously since they deal with storage locations. Data location affects the amount of gas used in a transaction and therefore can negatively impact smart contract development performance.
When using reference types, reference variables point a user to the location of value storage, and these can take up more than 32B of memory in size.
Two separate variables can refer to the exact location, and any change in one variable can affect the other. Several variables that point to the same address can be used to effect a change in a reference data type.
There are several reference data types in Solidity: fixed-sized arrays, dynamic-sized arrays, array members, byte arrays, string arrays, structs, and mapping.
Arrays are a group of variables of the same data type, with each variable having a unique index. Array size can be fixed or dynamic.
Arrays data structures are dependent on other data types. They keep these data in storage and simplify the process of repetition, storage, and search for variables or a subset of variables within a group.
We can retrieve a requested variable by using the unique index location.
Here’s an example of an array in Solidity:
pragma solidity ^0.5.10 // code illustration of array in solidity Contract SampleArray } uint [10] = MyIntArray ; }
Fixed-size arrays have a predefined size when they are declared.
Here’s an example of a fixed-size array in Solidity:
pragma solidity ^0.5.10 // code illustration of fixed-size array in solidity Contract SampleFixedSizeArray } uint[6] arrayName; }
In Solidity, we cannot use the new
keyword with a fixed-size array. Instead, the array’s data variables must be initialized inline, like so:
pragma solidity ^0.5.10 // code illustration of fixed-size array in solidity Contract SampleFixedSizeArray } uint [6] age = [ unit (60), 70, 80, 90, 100, 110] ;
They may also be initialized inline with a function:
pragma solidity ^0.5.10 // code illustration of fixed-size array in solidity Contract SampleFixedSizeArray } uint [6] age ; age = [ unit (60), 7, 8, 9, 10, 11] ;
Dynamic arrays do not have a predefined size when they are declared. Instead, their size is determined at run time.
Here’s an example of a dynamic-size array in Solidity:
pragma solidity ^0.5.10 // code illustration of fixed-size array in solidity Contract SampleDynamicSizeArray } int[] arrayName;
We can initialize a dynamic array either inline or by using the new
keyword like so:
pragma solidity ^0.5.10 // code illustration of dynamic-size array in solidity Contract SampleDynamicSizeArray } int[5] englishMarks = [uint(50), 60,70,80,90]; int[] scienceMarks = new int[](5);
Array members have the following properties:
After they are built, storage arrays have a fixed length. It can, however, be dynamic and determined by runtime parameters. The length of dynamically sized arrays is set to adjust their size.
Here’s an example of array members in Solidity:
pragma solidity ^0.5.10 // code illustration of array members in solidity int[] public array ; int length = array length; // get the length of the array array push(u); // Append to array array pop(); // Remove last element from array
Now let’s learn about two special arrays provided in Solidity: the byte array and the string array.
A Solidity byte array is a dynamic array that can hold any number of bytes. This differs from the bytes value type we discussed earlier, which can take 32B for each variable. A byte array holds all of the bytes together tightly.
The byte array can be used in the following ways:
Here’s an example of a byte array in Solidity:
pragma solidity ^0.5.10 // code illustration of byte array in solidity Contract SampleBytesArray { // as a state variable bytes simBytes = riBytes (2) // as divided code lines bytes simBytes ; simBytes = riBytes (8) // with directly assigned values simBytes = " Lorem Modi " ; // with values pushed into it simBytes. push ( byte(10) ) // as read/write length property simBytes. length = 5; // setting bytes length to 5 bytes
String arrays are dynamic, like byte arrays, but they have unique constraints. For example, string
does not have an index so it lacks array members such as length
, push
, and pop
. If three is a need to perform any of these functions, string variables should be converted to bytes first, and then converted back to strings after the operation
They can be composed of characters within a single or double quote.
Here’s an example of a string array in Solidity. Note that the strings are declared and the values are assigned directly:
pragma solidity ^0.5.10 // code illustration of a string array in solidity Contract SampleString String name = ' Lorem Modi " ; // convert back to bytes Bytes ByteName = bytes ( name ) ;
The struct reference type in Solidity refers to a new (or custom) data type. You can use the struct
keyword to define a structure, made up of multiple variables, which can be both value type and reference type.
In most cases, struct
is used to represent a record.
It’s important to note that because structs must be finite in size, they cannot contain members of their type. This is not to say that struct cannot contain struct; for example, struct A can contain struct B, but struct A cannot contain struct A.
Here’s an example of a struct
data type in Solidity:
pragma solidity ^0.5.10 // code illustration of string array in solidity Contract SampleStruct struct patient { string name; string age; uint16 gender; }
In Solidity, mapping functions similarly to a hashtable or dictionary in other programming languages.
Mapping is the most frequently used reference type in Solidity. Mapping types are used to store data in the form of key-value pairs, where the key can be any of the inbuilt data types except for reference types, and the value can be any type.
The mapping function can retrieve stored data using the supplied key.
Because Solidity mapping only provides an option for one data storage location, this data type is permitted for state elements.
The mapping type is declared using the mapping
keyword followed by data types for both key and value, separated by the =>
notation.
Here’s an example of a mapping type in Solidity:
pragma solidity ^0.5.10 // code illustration of mapping type in solidity Contract SampleMap mapping (unit => address) Variables;
In this guide, we covered the relation and application of Solidity value types and reference types in smart contract development.
I hope this was a helpful tutorial on what is ostensibly a complex topic for many developers.
Enjoy your Solidity development journey!
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — Start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
2 Replies to "The ultimate guide to data types in Solidity"
I like the tutorial but the solidity version its used in here is just too old to reference.
Hi Brian!
Glad that you found this tutorial helpful. However, this tutorial was written a year ago and this was the most used version at the time.
Thanks