The upcoming Solidity 5.0 version is coming with a couple of breaking changes, and you should make sure to learn about them. The full list of changes is quite big, but in this article I picked the most important one and explained them with short examples.
Most of the changes are not new features, but rather restrictions on the way current Solidity features are used. It forces the programmer to be more explicit, which help the compiler to better understand the programmer intentions.
PS: At the time of writing this article Solidity 5.0 was not released yet. You will have to wait a couple of month before you can use it.
Let’s see what is in this new release!
New constructor keyword
Before Solidity 5.0, constructors were declared with a function having the same name as the contract:
contract MyContract {
address owner;
function MyContract(address _owner) public {
owner = _owner;
}
}
This is annoying because it forces the programmer to change the name of the constructor if the name of the contract changes. But even more annoying is that it introduces a security risk. Let’s say that I misspell the name of my constructor. The contract will still deploy, but now any one is able to execute my (non-constructor) function and potential take control of the contract. In our example, anyone would be able to set the owner
variable, which is used in other functions for admin access control!
contract MyContract {
address owner;
/*
* //Ooops.., the 'm' of myContract() is lower case, but it's uppercase in the name of the contract!
*/
function myContract(address _owner) public {
owner = _owner;
}
}
To solve this problem, Solidity 5.0 introduces the constructor
keyword to define constructors:
contract MyContract {
address owner;
constructor(address _owner) public {
owner = _owner;
}
}
No need to keep in sync the constructor name and the contract name. Sweet!
New emit keyword
Before Solidity 5.0, to trigger an event you just had to reference the name of the event in a function. This can be confusing because this is exactly the same syntax as a function. When you see a function call in a Solidity contract, you don’t know if it’s actually a function call or an event:
struct User {
uint id;
string name;
}
event UserCreated(uint id, string name);
User[] users;
function createUser(uint id, string name) public {
users.push(User(id, name));
UserCreated(id, name); //Is this a function or an event?
}
To solve this, Solidity 5.0 introduces the emit
keyword when you trigger an event:
struct User {
uint id;
string name;
}
event UserCreated(uint id, string name);
User[] users;
function createUser(uint id, string name) public {
users.push(User(id, name));
emit UserCreated(id, name); //No doubt, this is an event!
}
Block-scoped variables
Before Solidity 5.0, Solidity was using function-scoped variables, like Javascript. This means that variables declared ANYWHERE inside a function could be seen from anywhere else in the function. Even if it looks weird, the below code is valid Solidity code:
function myFunc() public {
i = 2; // ?? Where is this declared?
// Other stuffs
// ...
// ...
// ...
// Buried deep below:
if(true) {
uint i; //The definition of i is lifted at the beginning of the function
}
}
Solidity 5.0 will replace the function scoping rules by block scoping rules. This is consistent with what most programming languages do. The code above would not work in Solidity 5.0. The inner block can see the variables in the outer scope, but the converse is not true:
function myFunc() public {
uint outer = 0;
inner++ // WRONG! Cannot see inner block variables
if(true) {
uint inner = 0;
outer++; //OK, can see outer block variables
}
}
Removed var keyword
Before solidity 5.0, you could use the var
keyword to declare a variable without specifying its type. The compiler infers the type of the variable based on the context. It finds the smallest type that can fit the data that is fed to the variable. The problem is, this simple way of inferring the type does not always find the right kind of variable. Let’s see why.
In the example below, the sum()
function can add numbers: sum(2) = 1 + 1, sum(3) = 1 + 2 + 3, etc… The compiler will assign the type uint8
(An 8 bit integer) to i
, which is the smallest type that can accommodate 1
; The maximum value that an uint8
can accommodate is 255 (2^8 -1). As long as to
is below 256, everything work. However, when to
is equal to 256 or greater, the contract will break: when i
reaches 255, i++
increments it for the next pass of the for
loop, but since i
has already reached the maximum value of its type (uint8
), it will “wrap up” and come back to the start of the range for the uint8
type, i.e 0. And then we are in for another cycle in the for
, from 0 to 255, and so forth and so on. We are stuck in an infinite loop!
contract MyContract {
function sum(uint to) view public returns(uint) {
uint sum;
for(var i = 1; i <= to; i++) {
sum += sum;
}
return sum;
}
}
To avoid this, we should have declared i
as an uint
, like to
. Because the compiler cannot figure this on its own, it was decided to remove altogether the var
keyword. Now you have to specify the type of all your variable, no more guessing by the compiler:
contract MyContract {
function sum(uint to) view public returns(uint) {
uint sum;
for(uint i = 1; i <= to; i++) {
sum += sum;
}
return sum;
}
}
Conclusion
If you want to learn more about the upcoming changes in Solidity 5.0, make sure to read the official documentation. There is also an interesting video by Christian Reitwiessner, the creator of Solidity
Solidity
Leave a Reply