Learning Solidity as a Javascript Developer
To read more articles like this, visit my blog
Solidity is a programming language used for writing smart contracts on the Ethereum blockchain. This can be your entry point to the blockchain world.
If you are already a front-end javascript developer, then learning Solidity will be a piece of cake.
And today I am going to feed you that cake.
Let’s learn the basic solidity syntax in the next five minutes or so…
Data Types
Javascript is a dynamically typed language. This means we can basically declare anything using let
and const
.
let name = "Mohammad Faisal";
let age = 34;
So, you can see that in javascript, the variables take the data type dynamically.
But in solidity, we have some basic data types.
String
We can declare a string using the string
keyword.
string name = "Mohammad Faisal";
Numbers
In Solidity, the number type is represented by uint256
type.
uint256 age = 34;
Now, Solidity represents numbers as uint256
(unsigned integer of 256 bits) because the Ethereum Virtual Machine (EVM) is a 256-bit machine.
It can process 256-bit numbers and operations on them natively. Therefore, using uint256
ensures that the EVM efficiently processes the numbers being used in smart contracts.
You can use uint
as a replacement to uint256
.
// The following lines are equivalent
uint age = 34;
uint256 age = 34;
There are other types, such as uint8
, uint16
, etc. They can be used to reduce gas fees. But, they will also limit the number of numbers that can be represented.
Boolean
Declaring a boolean is straightforward. Just use the bool
keyword
bool isHappy = false;
Address
In Solidity, the address
type is a special type used to represent Ethereum addresses. This is something new for people outside of the blockchain.
address public owner;
In this case, the owner
variable is declared as a public variable of type address
.
The public
keyword indicates that it can be accessed from outside the contract.
address payable recipient = 0x1234567890123456789012345678901234567890;
Here the recipient variable is a valid address.
Arrays
Declaring arrays is also super simple. Just add a suffix to the expected type array with []
.
To declare arrays of different types
uint[] numberArray =[1,2,3];
string[] stringArray = ["person 1" , "person 2"];
Now, arrays can have a fixed size,
uint[5] public myArray; // declares a fixed-size array with 5 elements
myArray[0] = 1; // assigns the value 1 to the first element of the array
Or it can have a dynamic size, Just like javascript.
uint[] public myDynamicArray; // declares a dynamic-size array
myDynamicArray.push(2); // adds the value 2 to the end of the array
myDynamicArray.push(3); // adds the value 3 to the end of the array
We even have the same properties and methods as javascript arrays like length
, push()
etc.
Declaring a multi-dimensional array is also very similar.
uint[3][2] public myMultiArray; // declares a 2-dimensional fixed-size array
myMultiArray[0][0] = 1; // assigns the value 1 to the first element of the first sub-array
myMultiArray[1][1] = 2; // assigns the value 2 to the second element of the second sub-array
Structs
Structs are like objects in javascript. We can declare a Person
object like the following.
struct Person {
string name;
uint age;
bool hasDriverLicense;
}
We can create a struct and assign values to it in the same way as Javascript.
// declares a variable of type Person
Person public myPerson;
myPerson.name = "Alice";
myPerson.age = 30;
myPerson.hasDriverLicense = true;
We can do it in a declarative way as well
Person memory p = Person("Bob", 25, false);
Pretty awesome right?
Mappings
Mappings are the same thing as Dictionary
in other languages. The way we declare a mapping
is
mapping (uint => string) public myMap;
Notice that we are declaring the types of the dictionary inside the () of the declaration.
The above code means,
The key
of the dictionary will be a uint
And the value must be a string
So, now we can assign values like the following,
myMap[34] = "Name";
To delete a key from the mapings
,
delete myMap[34];
Now you may wonder why we have so much more flexibility in javascript. We can assign anything to anything.
Well, that’s actually a good thing and a bad thing. The strict nature of solidity makes the applications secure. This is a major priority for solidity language and Ethereum blockchain.
Loops
You can copy-paste a looping code from javascript, and it will pretty much work exactly the same in solidity.
To loop through an array of values and calculate the sum,
uint[] values = [1 , 2 ];
uint sum = 0;
for(uint i=0; i < names.length; i++){
sum+= values[i];
}
So you can see that the code looping syntax is exactly the same in both languages.
Functions
Declaring functions in Solidity is different than what we do in Javascript.
Following is a simple example. This function takes two numbers and returns the sum of them.
function add(uint a, uint b) public pure returns (uint) {
return a + b;
}
Here is the breakdown
funciton
— We declare that it’s a function. Same as javascript
add
— The name of the function. Can be anything
(uint a, uint b)
— Two input parameters to the function. There can be any number of them.
public
-> The visibility of the function. The function can be accessed from anywhere.
pure
-> This keyword means that we are not modifying anything.
returns (uint)
-> We specify that we will return a value of type uint .
So now we are getting outside of our comfort zone. Let’s learn some new concepts in solidity.
Visibility Modifiers
We declared our function as public
. But what does that mean?
A function can be called from many places. For example, inside the contract or outside the contract. The same goes for variables as well.
This visibility modifier controls and limits the visibility of a function or a variable.
Here are the available types.
1.public
: Anyone can call it. The current or any other contract.
2.external
: The function can only be called by other contracts.
3.internal
: The function can only be called the current contract and any derived contracts.
4.private
: Similar to internal
The function can only be called the current contract, not by the derived contract.
What are function types?
Now one new thing we can see here is the keyword pure
. There are mainly two types of functions in solidity.
1. pure function
This function modifier indicates that the function does not read or modify the contract's state.
It is used for functions that perform mathematical computations or other operations that do not require access to the contract's storage.
function add(uint a, uint b) public pure returns (uint) {
return a + b;
}
In the above example, we are not reading or modifying anything. Just returning the sum of the function inputs.
2. View function
This function modifier indicates that the function does not modify the contract's state but may read data from the contract's storage.
It is used for functions that need to read data from the contract's state but do not modify it.
function getBalance(address account) public view returns (uint) {
return balances[account];
}
Here we are reading from the balances
array and accessing the value of the account
balance. So it’s a view
function.
3. Payable function
A payable
function can receive either as part of a transaction. It allows the contract to receive payments and interact with external accounts.
Here’s an example of a payable
function:
function buyTokens() public payable {
// code to buy tokens
}
4. Construct a function
A constructor is a special function declared with the constructor
keyword and is only executed once at the deployment of a contract.
contract MyContract {
uint myVar;
constructor(uint initialVal) {
myVar = initialVal;
}
}
Note that a contract can only have one constructor function, and the constructor function has the same name as the contract.
Modifiers
Modifiers are the like middlewares
in javascript.
If you need to run the same logic over and over again before executing every function, then modifiers
can help you with that.
Here is how you create one of the most common modifiers.
modifier onlyOwner() {
// Requires that the calling address is the owner of the contract.
require(msg.sender == owner, "Not the owner");
_;
}
The above code checks if the caller of the function is the owner.
The
msg
is a global variable which can be accessed from anywhere. So don’t get confuesed
We can attach our modifier to a function
// We attach our modifier onlyOwner
function doSomething(uint256 _number) public onlyOwner {
// This assignment is only performed if the modifier passes
// .. rest of the funciton code
}
So now, when you call the doSomething
function, first, the code inside the onlyOwner
modifier will be run.
If the code passes, then the code of doSomething
will execute.
This can reduce the amount of repeatable code in your application.
So. That was it. I hope you know Solidity's basics and are ready to write your first smart contract!
Have a wonderful day!
You can reach me via LinkedIn