Skip to main content
Create your own

Value vs. Reference Types in Solidity

Welcome back. In our last lesson, you built your first SimpleToken contract, defining its state with variables, initializing it with a constructor, and adding behavior with a transfer function. In doing so, you've already used several of Solidity's data types, such as uint256, string, address, and mapping.

Now, we will explore a crucial distinction in Solidity's type system that underpins how data is managed: the difference between value types and reference types. Understanding this concept is fundamental to writing secure and gas-efficient smart contracts. It directly impacts how you structure data, pass information between functions, and manage the contract's state.

By the end of this lesson, you will be able to distinguish between value types like uint, bool, and address, and reference types like arrays, structs, and mappings. This knowledge is essential for designing the more complex data models required for the stablecoins and security tokens you aim to build.

1. Value Types: Direct and Independent

Value types are the simplest data types in Solidity. A variable of a value type holds its data directly. When you assign one value-type variable to another, or pass it to a function, a completely independent copy is created.

Think of it like working with cells in a spreadsheet. If you copy the value from cell A1 (e.g., the number 100) and paste it into cell B1, B1 now also contains 100. If you then change B1 to 200, A1 remains 100. They are entirely separate.

The most common value types you will use are:

  • bool: Represents a boolean state, true or false.
  • uint / int: Unsigned and signed integers of various sizes (from uint8 to uint256). uint is an alias for uint256, the standard for token balances and numerical calculations.
  • address: Holds a 20-byte Ethereum address. This is fundamental for identifying users and other contracts.

The following video provides a clear, practical demonstration of these value types.

Value Types | Solidity 0.8

This video from the Smart Contract Programmer channel introduces the core value types in Solidity.

As you watch, pay attention to how each type is declared and initialized: Value vs. Reference: First, watch the introduction from the beginning to grasp the core conceptual difference. Boolean: See the simple bool example at this timestamp. Unsigned Integer: The next segment covers uint, explaining that it can only hold non-negative numbers. Watch from this section. Signed Integer: The video then explains int for both positive and negative numbers. Watch from this part. Address: Finally, see the declaration of an address type, which you've already used, from this section.

To solidify your understanding, the following article provides a good written summary of value types.

Solidity Data Types - A Complete Guide | Shardeum

This guide from Shardeum offers concise definitions for Solidity's data types.

Please read the section on Value Types Solidity. Start from the beginning of the section here and read through the descriptions of Addresses, Booleans, Signed Integers, and Unsigned Integers. Note the key sentence: "if you make changes in the value of the duplicated variable, the original variable remains unaffected."

2. Reference Types: Pointers to Data

Reference types are more complex. Instead of holding the value directly, a variable of a reference type stores the address or location where the actual data is kept. When you assign one reference-type variable to another, you are only copying the pointer, not the data itself. Both variables now point to the same underlying data.

Returning to the spreadsheet analogy, this is like creating a "linked cell". If cell B1 is linked to A1, and you change the value in A1 to 500, B1 will automatically update to 500 because it's just a reference to A1. Changing the data in one place affects all references to it.

From your data warehousing experience, this is conceptually similar to how different analytical queries or views can all point to a single, authoritative table in a database. Modifying the source table's data is reflected in all queries that reference it.

The main reference types are:

  • arrays: Collections of data, which can be fixed-size or dynamic.
  • structs: Custom data structures that allow you to group multiple variables, perfect for modeling complex objects.
  • mappings: Key-value stores, which you used for balanceOf in the SimpleToken contract.

Let's explore each of these.

Arrays

Arrays are collections of elements of the same type. Solidity supports two kinds:

  • Fixed-size arrays: uint[5] declares an array that always holds exactly 5 unsigned integers.
  • Dynamic arrays: uint[] declares an array that can grow or shrink in size.

The following video is an excellent guide to declaring, initializing, and manipulating arrays in Solidity.

Array | Solidity 0.8

This video, also from Smart Contract Programmer, focuses exclusively on arrays.

Follow along to understand how arrays work: Declaration and Initialization: Watch the first part to see how to declare and initialize dynamic and fixed-size arrays. Notice the syntax difference. Array Operations: The next segment demonstrates key operations. Pay close attention to how push adds an element, how pop removes the last element, and how delete works. It's important to note that delete resets an element to its default value (e.g., 0 for a uint) but does not change the array's length. Watch from this point.

Structs

Structs are one of the most powerful features in Solidity for data modeling. They allow you to define your own complex data types by grouping together variables. This is essential for creating representations of real-world objects, which will be critical for your goal of building security tokens.

For instance, to represent a security token holder, you might need more than just their balance. You might need to track their investor tier, whether they are KYC-verified, and their jurisdiction. A struct is perfect for this:

struct Investor {
    uint256 balance;
    bool isVerified;
    string investorTier;
    // ... other properties
}

This Investor struct bundles different pieces of information into a single, logical unit. You can then create variables of this type, such as a mapping from an address to an Investor struct.

Data Types & Storage - Solidity Course - Mintlify

This page from a Mintlify Solidity course provides a concise code example for structs.

Find the section titled Structs. Review the example to see how a struct is defined and then used to declare a variable.

Mappings

You've already encountered mappings: mapping(address => uint256) public balanceOf;. They are hash tables that store data as key-value pairs.

A key feature of mappings is that they are implicitly initialized such that every possible key exists and is mapped to a value of zero representation (e.g., 0, false, or the zero address). You don't "add" keys; you simply assign a value to a key. This makes them extremely efficient for lookups, such as retrieving a user's token balance.

3. Why This Distinction Matters: Data Locations and Gas

The difference between value and reference types is not just academic; it has profound consequences for gas costs, which is a measure of the computational effort required to execute operations on the Ethereum network.

In Solidity, data can exist in different locations:

  • storage: This is the permanent memory of the smart contract, written to the blockchain. State variables (those declared at the contract level, like totalSupply or balanceOf) reside in storage. Writing to storage is the most expensive operation in Ethereum.
  • memory: This is a temporary data location used during function execution. Data in memory is erased once the function call ends. It is cheaper to use than storage.
  • calldata: A special, read-only data location for external function arguments. It is the cheapest location for data.

When you pass a reference type like a struct or an array within a function, you must specify its data location (usually memory or calldata). Copying large arrays or structs from storage to memory consumes gas. Modifying a storage variable consumes even more.

Therefore, a key part of smart contract optimization is minimizing expensive storage operations. Understanding that reference types point to data in a specific location is the first step toward writing gas-efficient code. We will dive much deeper into data locations and gas optimization in Module 4, but it's important to begin connecting these concepts now.

Conclusion

In this lesson, you've explored the fundamental division in Solidity's type system. Let's summarize the key takeaways:

  • Value Types (uint, bool, address, etc.) hold their data directly. Assignments and function passes create independent copies.
  • Reference Types (arrays, structs, mappings) store a reference (a pointer) to the data's location. Assignments create a new pointer to the same data, not a copy of the data itself.
  • This distinction is critical because of how data is handled in different data locations (storage, memory), which directly impacts your contract's gas consumption and performance.

You now have a much more structured understanding of the data types you were introduced to in the last lesson. This foundation is essential for designing the robust data structures needed for tokenization.

In our next lesson, we will continue to build on the structure of a contract by examining visibility specifiers (public, private, internal, external). These control who can access your contract's state variables and functions, a cornerstone of smart contract security and design.

Can't find a good explanation? Sign up and we'll make it for you

Sign up