When starting a new web3 project, it’s important to make the right choices about the blockchain and smart contract language. These choices can significantly impact the overall success of your project as well as your success as a developer.
In this article, we'll compare three popular smart contract programming languages:
We'll explain the concepts and characteristics of each language in simple terms, making it easier for beginners to understand. Let’s dive in.
Solidity is a high-level, object-oriented language used to build smart contracts in platforms like Ethereum. Initially, Solidity aimed to be user-friendly, attracting developers by resembling JavaScript and simplifying learning. While it still values user-friendliness, its focus has shifted to enhancing security. Currently, Solidity has quite a few security pitfalls developers need to be aware of.
Some Solidity features include:
Cadence is designed by Flow, a blockchain known for helping to make web3 mainstream and working with major brands like Disney and the NBA. It ensures secure, clear, and approachable smart contract development.
Some Cadence features include:
Now, imagine contracts as Lego building blocks. Composability in web3 means one contract can be used as a foundation for others, adding their features together.
For instance, if a contract records game results on a blockchain, another contract can be built to show the best players. Another one could go even further and use past game results to predict future game odds for betting. But here's the catch: Because of how Solidity works, contracts can only talk to one another if the first contract has permission to access the second one, even if users can access both.
In Solidity, who can do what is controlled by protected functions in contracts. This means contracts know and check who is trying to access their protected areas.
Cadence changes how access works. Instead of using the old way where contracts need permission, it uses Capabilities. When you have a Capability, you can use it to get to a protected item such as a function or resource. This means the contract no longer has to define who's allowed access. You can only get to the protected item if you have a Capability, which you can use with "borrow()." So, the old "msg.sender" way isn't needed anymore!
The effects of composability are important. When contracts don't need to know beforehand who they're interacting with, users can easily interact with multiple contracts and their functions during a transaction if they have the right permissions (Capabilities). This also allows contracts to interact with one another directly without needing special permissions or preparations. The only condition is that the calling contract must have the required Capabilities.
Move, used in the Sui/Aptos blockchain, addresses challenges posed by established languages like Solidity. It ensures scarcity and access control for digital assets.
Move’s features include:
Let's illustrate the differences by comparing a simple smart contract that increments a value in Cadence, Solidity, and Move.
In Solidity, creating a contract that increments a value involves defining a contract, specifying the count variable, and creating functions to manipulate it. It uses explicit syntax for variable visibility and function declarations.
// SPDC-License-Identifier: MIT
pragma solidity ^0.8.17;
contract Counter {
uint public count;
// function to get the current count
function get() public view returns (uint) {
return count;
}
// function to increment count by 1
function inc() public {
count += 1;
}
// function to decrement count by 1
function dec() public {
count -=1;
}
}
Cadence's approach to incrementing a value is similar but emphasizes clarity. It utilizes a resource-oriented structure and straightforward syntax, making it easier for developers to create and manage digital assets.
pub contract Counter {
pub var count: Int
// function to increment count by 1
pub fun increment() {
self.count = self.count +1
}
// function to decrement count by 1
pub fun decrement() {
self.count = self.count – 1
}
pub fun get(): Int {
return self.count
}
init() {
self.count = 0
}
}
In Solidity, the visibility keyword comes before or after variable/function names, whereas Cadence consistently follows the visibility-type-name sequence.
Flow's network boasts higher transaction throughput than Ethereum, making Cadence more scalable. Additionally, Flow's support for contract updates enhances development.
Move introduces new concepts like modules, resources, and ownership control. A Move module creates an Incrementer resource, requiring the owner's signature for operations.
module incrementer_addr::increment {
use aptos_framework::account;
use std::signer;
struct Incrementer has key {
count: u64,
}
public entry fun increment(account: &signer) acquires Incrementer {
let signer_address = signer::address_of(account);
let c_ref = &mut borrow_global_mut<Incrementer>(signer_address).count;
*c_ref = *c_ref +1
}
public entry fun create_incrementer(account: &signer){
let incrementer = Incrementer {
count: 0
};
move_to(account, incrementer);
}
}
All three languages support composite types, allowing complex types from simpler ones. All are Turing complete, meaning they can handle any computation given enough resources.
While Solidity and Move require compilation, Cadence is interpreted. Cadence and Move employ a resource-oriented approach, securing digital ownership in one location.
When selecting a programming language like Solidity, Cadence, or Move, consider the needs of your project.
Ultimately, your choice will impact your project's success, so make an informed decision and enjoy your journey as a web3 developer!
Also published here.