Beginner Journey Learning Rust
Table of Contents
Overview
Motivation
- Cargo & Workspace
- Type System
- WebAssembly
- Elixir Rustler
Journey
Outro
Overview
Last week, I decided to code using Rust
. I’ve followed Rust since its initial version, reading many sources, and cases, and exploring its ecosystem such as any available libraries, and I have to admit, that the progress is really fast and rich.
For context, I’m a programmer who already used many programming languages, such as:
- VB (Visual Basic)
- PHP
- Python
- Ruby
- Javascript
- Golang
I’m using all of these languages at the production level. Since, 2022–2023 I want to learn new languages, and there are two categories that I want to learn
- Functional languages
- General languages
For the functional language, there are two candidates
- Clojure
- Elixir
For the functional language, I’ve decided to use Elixir
. But this story is not about it, this story is more about my decision for the general languages, and I’ve decided to chooseRust
.
Motivation
My interest in this language, Rust
, started since many L1 blockchain networks were built using Rust, such as:
- Polkadot
- Solana
- NEAR
I’m just amazed at the way they manage their codebase, including the verbosity of the language, it’s like Java, but with the performance of C/C++. Not just for Web3, many startups started using Rust for their backend system, like Dropbox and Discord:
For the Discord itself, as long as I know, they have two primary languages, Elixir
and Rust
.
If many people looking at Rust
from the perspective of system programming, low-level programming, or even the possibility of building an OS or kernel, I have different perspectives or factors that influence me to choose Rust
- Cargo & Workspace
- Type System
- Web Assembly
- Integration with other high-level languages, especially
Elixir
throughRustler
Cargo & Workspace
For me this factor is important. I have an experience maintaining a large codebase, and if we don’t have any tools that support this need, then it's the beginning of chaos. And what got me interested in this language, is because of these features.
The Cargo Workspace
is like Elixir Umbrella
, it is a feature that helps us to maintain larger codebases which separated into multiple child packages.
In the beginning, in Rust
, there are two categories of packages
- binary crate
- library crate
What is crate?
A crate is the smallest amount of code that the Rust compiler considers at a time
Source:
Binary Crate
Binary crates are programs you can compile to an executable that you can run, such as a command-line program or a server
Library Crate
Library crates don’t have a
main
function, and they don’t compile to an executable. Instead, they define functionality intended to be shared with multiple projects
Now, what if we have to maintain a codebase that has multiple binaries and multiple libraries? In other languages, the solution will depend on the engineer’s opinions, if we have five engineers, then we have five possibilities for different solutions to maintain the codebase.
Rust gives us a solution through its features, called Cargo Workspace
. For the short story, it's possible to maintain binary and library crates like this:
├── Cargo.lock
├── Cargo.toml
├── add_one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
Example of Cargo.toml
to produce a codebase like the above:
[workspace]
members = [
"adder",
"add_one",
]
Examples of other projects using Rust
that already using this feature:
Type System
The type system feature Rust
just reminds me of a language that also has the same feature, which is Scala
. When I first time tried Scala
, I have to admit that language has a very rich type system that possible to build a good abstraction level.
What kind of type system that provided by Rust
?
Example of snippets:
fn to_vec<A: Clone>(xs: &[A]) -> Vec<A> {
if xs.is_empty() {
return vec![];
}
let first: A = xs[0].clone();
let mut rest: Vec<A> = to_vec(&xs[1..]);
rest.insert(0, first);
rest
}
impl<T> Option<T> {
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
}
Like I’ve said before, in Rust
, with its rich type system included, we will possibly build a rich abstraction that expresses our business needs, but without any overtime overhead, which is called zero-cost-abstraction.
WebAssembly
I’m working on the Web3 industry for now. I’ve been working using Solidity to build smart contract in Ethereum / Polygon network. There are other networks, that already provide smart contract but in web assembly ( wasm ), such as:
- Polkadot
- Solana
- NEAR
- Cosmos
One thing that pushed me to choose Rust
, because there are a lot of libraries that have already proven working or building a wasm in rust.
Elixir Rustler
Like I’ve said before at the beginning of this story, I’ve decided that for the functional languages, I would choose Elixir
. In Elixir
or Erlang
, there is a concept called as NIF
( Native Implemented Function ).
The way to extend Erlang software through loading and executing native pieces of software
What is Rustler
?
Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no ways to crash the BEAM (Erlang VM). The library provides facilities for generating the boilerplate for interacting with the BEAM, handles encoding and decoding of Erlang terms, and catches rust panics before they unwind into C.
Source:
By using Rustler
, it gives us the possibility to build a native library to extend Erlang BEAM
, and load it into our Elixir
codebase. Example cases:
I’ve just been thinking that if we are using Rust
through Rustler
and use it in Elixir
, it means, we’ve got:
The concurrent level of Erlang, the beauty of Ruby’s syntax, with the performance of low-level
What else do we expect from this combination made from heaven?
Journey
Although I’ve been following Rust
from its initial version, I started coding (really coding experience) just last week, and this is the result:
It is just a simple REST API for user registration and login, It’s a really simple use case, but I’ve already learned about:
- Actix framework
- A pointer references high-level abstractions such as
Box
,Arc
- Type associated system
- Lifetime and borrowing for memory management
- Codebase structure
And from this journey, I’m really excited to use Rust
, and want to learn more about this language.
Outro
I hope this story can help others to motivate or at least start looking for the Rust
language, although just for hobbyist projects.