Due to the statically typed nature of Solidity, value types need to be specified for each variable. Value types indicate the type and in some cases the size of the value that should be allowed as a value to ensure that unexpected values are set that could create problems within your smart contract. The way I like to interpret this concept is by envisioning the design of a database table schema within the smart contract. Each variable you set is a column within the database and for each column you need to set the rules of what type of value can be stored and what the maximum length that the value can be. The behavior of this storage is not the same between a smart contract and database, but the declaration of a variable's attributes are.
An important distinction to call out with this comparison is that the value lengths have an impact on blockchain computing power and thus gas. While I haven’t talked much about gas yet, it is important to call out because gas is something that will be a continual focus when developing and optimizing smart contracts.
Before we can think about that, let us take a look at the various data types that are supported in Solidity.
Booleans (bool) - Constant true/false values that can be evaluated using comparison operators (!, &&, ||, ==, !=)
Unsigned Integers (uint) - Integers that do not contain a size suffix (i.e. indication if integer is positive or negative). Like signed integers, when not specified, the default maximum bits allowed are 256. Maximum bits can be assigned by appending a numerical value in steps of 8 to uint like uint8 or uint32.
Signed Integers (int) - Integers that contain a size suffix (i.e. indication if integer is positive or negative). Like unsigned integers, when not specified, the default maximum bits allowed are 256. Maximum bits can be assigned by appending a numerical value in steps of 8 to int like int8 or int32.
Address (address) - The identification of an Ethereum address. There are two types of Ethereum addresses, Externally Owned Address (EOAs) and Contract address. The EOAs are what you typically interact with when transferring funds between public addresses, while the contract address is generated when a smart contract is deployed to the Ethereum blockchain. This is the address that is used to identify which smart contract transactions are occurring from on a blockchain if they aren’t peer to peer and can act as a storage of ether. While the address keyword is the data type that represents both of these types of addresses, Solidity has a modifier keyword of address payable, that adds the following methods to the variable:
balance = Queries the balance of an address.
transfer = Sends Ether, in units of wei, to a payable address. If the transfer fails due to balance of the contract or the receiver rejects it, the function fails and reverts.
send = Similar to transfer, but instead of reverting on failure it returns false.
call = Constructs a message call with data payload
delegatecall = Similar to call, but when used it replaces the contracts code with an address.
Fixed Bytes - Holds a sequence of bytes up to a maximum of 32. The value limit can be incremented in steps of 1. This is also a sibling to string, which will allow you to store string values, but bytes require less computing power and gas than string so it is common to convert strings to bytes to store string values.
The two value types below are soon to be supported, but not yet useable:
Unsigned Floating Point Numbers (Soon to be supported) - Numerical values that contain decimal points, but do not contain a size suffix (i.e. indication if integer is positive or negative). These values are structured in the format of ufixedMxN, where M represents the maximum bits and N represents maximum decimal points. M must be divisible by 8 (in a similar nature to the steps for integers) and N must be between 0 and 80, inclusive. The default bit amount is 128 and decimal points is 18.
Signed Floating Point Numbers (Soon to be supported) - Numerical values that contain decimal points, but do not contain a size suffix (i.e. indication if integer is positive or negative). These values are structured in the format of fixedMxN, where M represents the maximum bits and N represents maximum decimal points. M must be divisible by 8 (in a similar nature to the steps for integers) and N must be between 0 and 80, inclusive. The default bit amount is 128 and decimal points is 18.
Pulling it all together
Value types are required to be prepended to variables in order to let the compiler know what type of data it should evaluate. There is overlap in these values with most programming languages so it shouldn’t be something new to developers. When getting comfortable with writing your code it is fine to be liberal with the value sizes and even the types you choose, but as you work towards production-ready applications, more conscious design efforts should be made to limit gas consumption.