Introduction to basic types in Solidity.
undefined
, null
, or none
. Because of this, each type has a default value. If you declare a variable without assigning a value, it will instead have the default value for that type. This property can lead to some tricky bugs until you get used to it.
uint256
into a int8
, you need to cast twice:
true
or false
. Solidity does not have the concept of truthy or falsey, and non-boolean values cannot be cast to bools by design. The short conversation in this issue explains why, and explains the philosophy why.
!
, &&
, ||
, ==
, !=
) apply to booleans. Short-circuiting rules do apply, which can sometimes be used for gas savings since if the first operator in an &&
is false
or ||
is true
, the second will not be evaluated. For example, the following code will execute without an error, despite the divide by zero in the second statement.
>
or <
with booleans, because they cannot be implicitly or explicitly cast to a type that uses those operators.
0.8.17
.
Floating point numbers are not supported and are not likely to be. Floating precision includes an inherent element of ambiguity that doesn’t work for explicit environments like blockchains.
type(<type>).min
and type(<type>).max
. For example, type(uint).min
is 0, and type(uint).max
is equal to 2^256-1.
An overflow or underflow will cause a transaction to revert, unless it occurs in a code block that is marked as unchecked.
uint
vs. int
uint
over int
when it is known that a value will never (or should never) be below zero. This practice helps you write more secure code by requiring you to declare whether or not a given value should be allowed to be negative. Use uint
for values that should not, such as array indexes, account balances, etc. and int
for a value that does need to be negative.
uint8
to uint256
, and the same for int
.
Smaller sized integers are used to optimize gas usage in storage operations, but there is a cost. The EVM operates with 256 bit words, so operations involving smaller data types must be cast first, which costs gas.
uint
is an alias for uint256
and can be considered the default.
<=
, <
, ==
, !=
, >=
, >
) and arithmetic (+
, -
, *
, /
, %
, **
) operators are present and work as expected. You can also use bit and shift operators.
uint
and int
variants can be compared directly, such as uint8
and uint256
, but you must cast one value to compare a uint
to an int
.
address payable
is a variant of address
that allows you to use the transfer
and send
methods. This distinction helps prevent sending Ether, or other tokens, to a contract that is not designed to receive it. If that were to happen, the Ether would be lost.
Addresses are not strings and do not need quotes when represented literally, but conversions from bytes20
and uint160
are allowed.
balance
returns the balance of an address, and transfer
, mentioned above, can be used to send ether
.
call
, delegatecall
, and staticcall
, which can be used to call functions deployed in other contracts.
+
, but as of 0.8.12, you can use string.concat(first, second)
. They are limited to printable characters and escaped characters. Casting other data types to string
is at best tricky, and sometimes impossible.
Generally speaking, you should be deliberate when working with strings inside of a smart contract. Don’t be afraid to use them when appropriate, but if possible, craft and display messages on the front end rather than spending gas to assemble them on the back end.
uint
, but not implicitly. They are limited to 256 members.
constant
and immutable
are not fully implemented. Both are supported on value types, and constant
can also be used with strings.