Beginners Guide to Solidity Development - Episode 4
In this episode we will be talking about variables and the types variables are supposed and allowed to have in Solidity.
Types and variables are the core foundation that smart contracts are built on top of, so this is a basic, but very important concept to learn about.
Strong and Static Typing
Solidity is a strongly, statically typed language. This means two things:
Strong typing means that when we declare a variable then it will only ever refer to values of one single type, so when we first say that some variable say X should be a number than we can't later put a string or a boolean in there.
Statically typed means that the compiler during compilation when Solidity is transformed into Ethereum bytecode, that is the time where type checking occurs and these two things are important.
And Solidity made the choiceto be a strongly statically typed language to be able to be relatively performant because the compiler is able to optimize the program quite a bit because it is already able to know what types the different values are so it knows how much space it needs to allocate in the different blockchain components. And it also allows the compiler to catch some bugs, or allows you to catch some bugs because the compiler can recognize when you try to use something of one type as something else which we usually we don't actually want to do.
Now, this is not perfect because Solidity is not an ML-style statically typed language but it can help us a little bit in this regard which is really nice. However, just something to keep in mind.
Now, on its base, Solidity only supports a handful of different types, the most basic one is the boolean type which is only one bit, it can either be true or it can be false. And booleans are really used to keep track of flags like if someone already did some action before. And of course, when we compare different values we get a boolean back as a result which we can use to see if something happened or not.
Now, besides booleans, Solidity also has a support for full numbers, integer numbers both signed and unsigned ones which mean that you can use both positive numbers and signed numbers are positive and negative numbers. Now, usually when we only write int or uint which is short for unsigned integer then we are working with base 256 numbers. That means that numbers can be very big and this is the implementations detail that allows, because the compiler, the Ethereum bytecode likes working with a 256-bit number because it already uses 256-bit numbers for a lot of its internal workings because it uses a lot of cryptographic hashing functions. It also means that we usually have enough space to perform arithmetic in because the numbers usually won't go beyond 256 bit. But, you can also use smaller numbers if you are sure that your numbers won't go beyond the limit of 8 bit,16 bit, 32, 64, 128 bit which can improve the speed of your code a little bit and more importantly reduce the gas cost of your code a little bit, but of course this should only be done after you already written your contract and you are relatively sure it works.
It's important to mention that there are two things that Solidity does not do for you:
First, it does not allow working with floating point numbers, no decimals which means that you need to keep track of the precision of your numbers outside of the blockchain. So if you are working with say, a monetary amount then you need to think first where to put the decimal and convert the numbers outside of the smart contract by multiplying them so they are large enough and afterwards when you get the value out dividing them by 10 to the same power to make sure that the decimal is back in place.
What Ethereum will also not do for you is perform overflow/underflow checking. And this means if you end up with the result that is too big for to store in one of these numeric types then it will just rule over and start counting at the other end. And this might seriously brake smart contracts. There are some libraries that allow you to do that the duty checks for you if you use them and we will look at those in the later episode because this is something very important that we need to keep in mind of Solidity that many other programming languages do perform for you.
Addresses, Enums, Arrays
Now Solidity has support for a couple of other basic types, it supports address types which you can see as a opaque type that stores the location of another smart contract or a person's wallet address and on an address you can perform all kinds of calls like checking how much ether this address has and we will be talking about that in a later episode.
Furthermore, Ethereum supports enumerables which are variables or a type that keeps track of one option out of multiple options. So, here you see an example where I've specified that we want to keep track of which drink someone likes and this can be one of these four listed choices here.
There, Ethereum also has support for both fixed-size arrays of at most 32 bytes long and dynamically sized arrays which might be even bigger and can be resized but have some other restrictions. We will be talking more about arrays in a later episode. They are really important when you try to keep track of new data that might be added over time to your smart contracts.
Mappings and Structs
And then, finally, there are a couple of reference types. These are types that internally store other types. We have structs which you can see as a group of other types and each of these things instruct, like each of its properties has its own name. And you could, for instance, store a representation of a user and in there store the first name, or the last name, or email address, or Ethereum address, things like that and combine them. And we will talk about structs in a more detail in a later episode as well.
And finally, we have mappings, and mappings allow you to lookup a value when you already have a different value and this allows as to keep track of arbitrary data by storing only reference value like identifier to it, Mappings do have some drawback as well, they are sort of like associative arrays that you might know from other languages, but not completely, we will be talking more about that in a later episode as well.
When you have the type, you can convert this type to a different type and when you make the numeric value bigger than this is not a problem at all and it will just happen for you automatically which is really nice because now data has lost, that means that compiler can just do that without being scared that something might go wrong.
However, if you do want to compare between types which sometimes we do want even do some information might get lost you can do so by repping the original value with parentheses and putting the name of a new type in front of it like shown here in this example.
It's important, as a final remark of this episode, that when we declare a type and we try to refer to it then it will already have a default value and this default value is some kind of empty value which for numbers is zero and for strings and byte arrays it is the empty string. And this, for booleans is false and it's important that you understand that for Solidity there is no difference between something that does not exist yet and something that is zero and sometimes this might be a problem, we will be talking more about this when we talk about structs and mappings and then you will see some examples of when exactly this is a problem and also how we can keep this in mind, can mitigate that problem.