# Advanced Solidity Datatypes Explained with Code Examples

🛑This is a long technical session, but if you manage to go through it you will come out a bad-ass solidity datatypes veteran!  
  
Solidity is a statically typed language used for writing smart contracts and building decentralized applications (DApps) on the Ethereum blockchain. It offers a wide range of data types to handle different kinds of data. Understanding these data types is crucial for writing efficient and secure smart contracts. Here, we will explore the advanced datatypes in Solidity and provide code examples to illustrate their usage.

Let's start getting technical!  
  
Value Types

Value types in Solidity store data directly in memory and are passed by value. But wait what is this `memory` thing?  

In technical terms, memory in Solidity refers to a temporary storage area where variables are stored during the execution of a function or a contract. It is a part of the Ethereum Virtual Machine (EVM) and is separate from the storage area where variables are permanently stored on the blockchain.

Here are some key points about memory in Solidity:

* Memory is used to store variables that are needed temporarily during the execution of a function or a contract.
    
* When you define a local variable in Solidity, it is stored in memory and then pushed to the stack for execution.
    
* Memory code is executed on the stack, which is a temporary storage area used by the EVM to bring data from other storage areas to work on them.
    
* The stack has a maximum depth of 1024 elements and supports the word size of 256 bits.
    
* Variables stored in memory are not stored simultaneously in memory and stack. Instead, they are moved from memory to the stack when needed for execution.
    
* This separation between memory and stack is cost-efficient, as it allows the EVM to optimize the usage of resources.
    

It is important to note that memory is different from storage in Solidity:

* Storage refers to variables that are permanently stored on the blockchain. State variables, which are variables declared outside of functions, are by default storage and written permanently to the blockchain.
    
* Memory, on the other hand, is a temporary storage area used during the execution of a function or a contract.
    
* Variables stored in storage can be accessed and modified by other contracts or external entities, while variables stored in memory are local to the function or contract and are not accessible from outside.
    

By understanding the concept of memory in Solidity, you can effectively manage the storage and manipulation of variables in your smart contracts.  
  
So back to value types:

**A. Integers**: Solidity provides both signed and unsigned integers of various sizes. The `uint` type is used for unsigned integers, while the `int` type is used for signed integers. Examples:

```solidity
uint256 public myUint = 100;
int8 public myInt = -10;
```

So if you are curios enough you probably starting to thing why do we need these typings for just a number variable? Perfect her is why,  
In Solidity, the availability of different-sized integers, such as uint8, uint16, uint32, int8, int16, int32, etc., serves several important purposes:

1. Efficient memory usage: By allowing developers to specify the size of integers, Solidity enables more efficient memory usage. For example, if you know that a variable will never exceed a certain range of values, you can use a smaller-sized integer to conserve memory. This can be particularly important in resource-constrained environments like blockchain networks.
    
2. Optimization of gas costs: Gas is the measure of computational effort required to execute operations on the Ethereum network. By using integers with smaller sizes, you can reduce the gas costs associated with storing and manipulating these variables. This optimization can lead to more cost-effective smart contracts.
    
3. Data validation and range restrictions: Different-sized integers allow developers to enforce specific range restrictions on variables. For example, if you have a variable that should only store values between 0 and 255, you can use uint8 to limit the range and prevent unintended values from being assigned.
    
4. Interoperability and integration: Solidity is designed to interact with other programming languages and systems. By providing different-sized integers, Solidity aligns with the capabilities and conventions of other languages, making it easier to integrate with existing systems and ensure compatibility.
    

So You can now see the availability of different-sized integers in Solidity offers flexibility, efficiency, and control over memory usage and gas costs. It allows developers to optimize their smart contracts and tailor the variables to specific requirements, leading to more efficient and secure blockchain applications.

**B. Boolean**: The `bool` type represents a boolean value, which can be either `true` or `false`. I like to think that this is the most simple type to go by.

```solidity
bool public isReady = true;
```

**C. Addresses**: The `address` type represents Ethereum account addresses. It can hold a 20-byte value and is used for interacting with other contracts or transferring balances.

```solidity
address public myAddress = 0x1234567890123456789012345678901234567890;
```

Right, the address type serves as a key cornerstone in Solidity and the Ethereum Virtual Machine (EVM) overall. Here are some important points to understand about the address type:

1. Functionality: The address type provides several built-in functions and members that allow you to interact with the account at a specific address. These functions include retrieving the balance of the address, sending funds to the address, and executing low-level calls to the address. These functionalities enable smart contracts to interact with other contracts or transfer balances securely.
    
2. Readability and type safety: Using the address type instead of a generic uint160 or bytes20 provides improved readability and type safety in your smart contracts. It clearly communicates that the variable is intended to store an Ethereum address, making the code more understandable for other developers.
    
3. Address types and inheritance: The address type serves as a base for all contracts. Contracts inherit certain members and functions from the address type, allowing you to access the functionality of the address type directly within your contracts. This inheritance simplifies the interaction with addresses and provides a consistent interface for address-related operations.
    
4. Address vs. address payable: Solidity also provides the address payable type, which is identical to the address type but includes additional members such as `transfer(...)` and `send(...)`. The address payable type is used specifically for addresses that can receive Ether, distinguishing them from plain addresses that are not designed to receive Ether. This differentiation ensures that Ether is sent only to addresses that are capable of handling it.
    

In short, the address type in Solidity is essential for interacting with Ethereum accounts, transferring balances, and executing low-level calls. It improves code readability, provides type safety, and enables powerful functionalities within smart contracts.

**D. Enums**: Enums in Solidity are user-defined data types that allow you to assign names to integral constants. They provide a way to define a set of related values and restrict a variable to have only one predefined value from that set. Enums are useful for creating custom data types with a limited set of options, making the code more readable, maintainable, and bug-resistant.

To define an enum in Solidity, you use the `enum` keyword followed by the enum name and a set of curly braces containing the values that the enum will contain. For example:

```solidity
enum Color { RED, GREEN, BLUE }
```

In this example, the enum `Color` is defined with three possible values: `RED`, `GREEN`, and `BLUE`. Each value in the enum is automatically assigned an integer value starting from 0, so `RED` is assigned 0, `GREEN` is assigned 1, and `BLUE` is assigned 2.

You can declare variables of the enum type and assign them one of the predefined values. For example:

```solidity
Color public myColor = Color.RED;
```

In this case, `myColor` is a variable of type `Color` and it is assigned the value `RED` from the `Color` enum.

Some key points to understand about enums in Solidity include:

* Enums are treated as numbers internally, and Solidity automatically converts them to unsigned integers.
    
* An enum should have at least one value in the enumerated list, and the values cannot be numbers or boolean values.
    
* Enums can be declared at the file level, outside of contract or library definitions.
    
* Enums can be used as function parameters and as keys in mappings.
    

Okay let's wrap it up, enums in Solidity provide a powerful and convenient way to define user-defined data types with a fixed set of values, making the code more expressive and reducing the chances of bugs. They are a fundamental tool in Solidity programming for creating custom data types and improving code organization and readability.

**E. Bytes**: The `bytes` type is used to store fixed-sized byte arrays, while the `string` type is used for dynamic-sized character arrays. Example:

```solidity
bytes1 public myByte = 0x12;
string public myString = "Hello, World!";
```

Let's get a little bit technical with bytes.

1. Representation at the low-level: In Solidity, bytes are represented as arrays of bytes, where each element of the array represents a single byte. The size of the byte array is fixed and specified by the bytes type declaration. For example, `bytes1` represents a single byte, `bytes2` represents two bytes, and so on.
    
2. Storage and manipulation: Fixed-sized byte arrays, such as `bytes1`, `bytes2`, etc., are useful when you know the exact size of the data you want to store. We have talked about this earlier if you remember! Bytes typings provide efficient storage and manipulation of binary data. You can access individual bytes in the array using indexing, and you can perform bitwise operations, such as shifting and bitwise AND/OR, on the byte array.
    
3. Conversion between bytes and string: Solidity provides built-in functions to convert between bytes and string. The `bytes` type can be converted to a string using the `string` typecast, and a string can be converted to bytes using the `bytes` typecast. However, it's important to note that the conversion from bytes to string and vice versa can be expensive in terms of gas costs, especially for large data sizes. Therefore, it's recommended to use bytes for binary data and string for textual data whenever possible.
    

So that was a bit of Value Types, now let us see how we can apply these types with more advanced typing cases. Yes, we are not done🥹.  
*  
\-Let's get technical!*

## Reference Types

Reference types in Solidity store reference to data and are passed by reference. They include:

1. **Arrays**: Solidity supports both fixed-sized and dynamic-sized arrays. Arrays are used to store multiple values of the same type. Example:
    

```solidity
uint256[] public myArray;
```

In the code snippet `uint256[] public myArray;` the `myArray` variable is declared as an array of type `uint256`. This means that `myArray` can store multiple values of type `uint256`.

To relate this to the section we saw above about the `uint` type, `uint256` is a specific subtype of the `uint` type in Solidity. The `uint` type is used to represent unsigned integers, which are non-negative whole numbers. The `uint256` subtype specifically represents unsigned integers with a size of 256 bits, allowing for a wider range of values to be stored.

By declaring `myArray` as an array of `uint256`, we are specifying that each element in the array can hold a value of type `uint256`. This allows us to store and manipulate multiple unsigned integer values within the array.

1. **Strings**: Strings are used to store dynamic-sized character arrays. Example:
    

```solidity
string[] public myDynamicArray;
```

In the code snippet `string[] public myDynamicArray;`, the `myDynamicArray` variable is declared as an array of type `string`. This means that `myDynamicArray` can store multiple values of type `string`.

To relate this to the section we saw earlier about bytes, the `string` type in Solidity is used to store dynamic-sized character arrays, similar to how the `bytes` type is used to store fixed-sized byte arrays. While `bytes` are used for binary data, `string` is specifically designed for storing textual data.

In the context of the code snippet, `myDynamicArray` is an array that can hold multiple string values. Each element in the array can store a dynamic-sized character array, allowing for flexibility in the length of the strings that can be stored.

It's important to note that strings in Solidity are stored as arrays of bytes internally. Each character in the string is represented by one or more bytes, depending on the character's encoding. Solidity provides built-in functions and operators to manipulate and access individual characters within a string.

1. **Structs**: Structs allow you to define custom datatypes that can contain both value types and reference types. They are useful for organizing related data into a single unit. Example:
    

```solidity
struct Person {
    string name;
    uint256 age;
}
Person public myPerson = Person("John", 30);
```

In the code snippet `struct Person { string name; uint256 age; } Person public myPerson = Person("John", 30);`, the `Person` struct is defined as a custom datatype that contains two fields: `name` of type `string` and `age` of type `uint256`.

Structs in Solidity allow you to create composite data types that can hold multiple values of different types. They are useful for organizing related data into a single unit. In this example, the `Person` struct represents a person's information, with the `name` field storing the person's name as a string and the `age` field storing the person's age as a `uint256`.

The `myPerson` variable is declared as a public variable of type `Person`. It is initialized with the values "John" for the `name` field and 30 for the `age` field. This allows you to create an instance of the `Person` struct and access its fields.

1. **Mappings**: Mappings are key-value data structures similar to hash tables or dictionaries in other programming languages. They allow you to store and retrieve data based on a unique key. Example:
    

```solidity
mapping(address => uint256) public balances;
```

In this example, the `balances` mapping is used to store and retrieve `uint256` values based on unique `address` keys. Each `address` key is associated with a corresponding `uint256` value. This allows you to keep track of balances or other data associated with specific addresses.

By declaring `balances` as a public mapping, it can be accessed and modified by other contracts or external entities. The `public` visibility modifier generates a getter function automatically, allowing other contracts or external entities to retrieve the values stored in the mapping.  
  
Oh yeah, keep diving general🫡

## Visibility Modifiers

In Solidity, visibility modifiers determine how functions and state variables can be accessed. They include:

1. **Public**: Public functions and state variables can be accessed from any other contract or externally. Example:
    

```solidity
uint256 public myVariable = 10;

function myFunction() public {
    // Function code here
}
```

First, the `uint256` state variable `myVariable` is declared as `public`. This means that the value of `myVariable` can be accessed from any other contract or externally. The `public` visibility modifier automatically generates a getter function for `myVariable`, allowing other contracts or external entities to retrieve its value.

In this example, `myVariable` is initialized with the value 10. Since it is declared as `public`, its value can be read by other contracts or external entities using the generated getter function.

Next, the `myFunction` function is declared with the `public` visibility modifier. This means that the function can be called from any other contract or externally. The function code can be written within the function body.

By declaring a function as `public`, it can be accessed and called by other contracts or external entities. This allows for interaction with the contract and execution of the function's code.

1. **Private**: Private functions and state variables can only be accessed from within the same contract. Example:
    

```solidity
uint256 private myVariable = 10;

function myFunction() private {
    // Function code here
}
```

First, the `uint256` state variable `myVariable` is declared as `private`. This means that the value of `myVariable` can only be accessed from within the same contract. Other contracts or external entities cannot directly access or read the value of `myVariable`.

In this example, `myVariable` is initialized with the value 10. Since it is declared as `private`, its value can only be accessed and modified within the same contract. This provides encapsulation and restricts direct access to the variable from external sources.

Next, the `myFunction` function is declared with the `private` visibility modifier. This means that the function can only be called from within the same contract. Other contracts or external entities cannot directly call or execute the `myFunction` function.

By declaring a function as `private`, it ensures that the function's code can only be executed within the same contract. This allows for encapsulation and restricts the visibility and accessibility of the function to the contract itself.

Are you getting the flow now right?

1. **Internal**: Internal functions and state variables can only be accessed from within the same contract or contracts derived from it. Example:
    

```solidity
uint256 internal myVariable = 10;

function myFunction() internal {
    // Function code here
}
```

1. **External**: External functions can only be called from outside the contract. They cannot be accessed internally or from derived contracts. Example:
    

```solidity
function myFunction() external {
    // Function code here
}
```

## BONUS✨

##   
Function Modifiers

Function modifiers are used to modify the behavior of functions. They include:

1. **View**: The `view` modifier specifies that the function does not modify the contract's state. It is used for reading data from the blockchain. Example:
    

```solidity
function myFunction() public view returns (uint256) {
    // Function code here
}
```

1. **Returns**: The `returns` keyword is used to specify the return type of a function. Example:
    

```solidity
function myFunction() public returns (uint256) {
    // Function code here
}
```

Okay, that's enough! , I am thinking of having a deep dive into the EVM and getting even more technical with it. See you in the next one🫡
