Get started with Rust

null

The C programming language has truly passed the test of time. There are very few environments where it does not thrive. This is mainly due to its high execution performance, which, unfortunately, comes at a price: C does not support many of the features expected in a modern programming language.

Mozilla Research's Rust is an attempt to create a better mousetrap. Its language design remains focused on high performance and being close to hardware.

However, its syntax and compiler also take advantage of the various benefits offered by modern programming language research. Given that Mozilla's mission is the creation of an 'open web', it should not be surprising that the company is working tirelessly to bring its latest brainchild to the web. 

While Rust can, in theory, run on the client via systems such as Emscripten, its real power lies in the creation of efficient backend services.

How to start using Rust

 The Rust installer provides a semi-graphic installation environment

 The Rust installer provides a semi-graphic installation environment

While package managers such as 'apt-get' surely made developer's life easier, package list maintainers are, by and large, known to be no friends of excessive speed. Because of that, many, if not most, distributions' package caches are heavily outdated.

The Rust team has solved this problem by providing a dedicated installation script, which sets up the system it is run on efficiently. Deployment, then, is a two-step process: first, make sure that the CURL downloader/parser is available:

tamhan@tamhan-thinkpad:~$ sudo apt-get install curl 
[sudo] password for tamhan: 
Reading package lists… Done…

Then, in the second step, download the installer and pass it on to 'sh' using the pipe operator. 'Sh' is a shorthand for the default shell interpreter of your workstation, which will then proceed to run the code at hand:

tamhan@tamhan-thinkpad:~$ curl https://sh.rustup.rs -sSf | sh 
info: downloading installer

During the installation, the Rust installer will display a variety of prompts similar in appearance to the ones shown in the picture on the right. Simply follow them to achieve a default installation. 

In some cases, the Rust deployment will fail with an error which is similar to "error: could not write rcfile file: '/home/tamhan/.bash_profile' ". If this happens during installation, use 'sudo -s' to get a root shell, and then rinse and repeat to proceed.

Run a sample

With that out of the way, it is time to run our first small program. Rust files, by default, have the file extension '.rs'. Create a file called 'firsttest.rs', and then provide it with the following piece  of code:

fn main() {
    println!("Hello World!");
}

C and C++ programmers often wonder why invocations of the 'println' method require the use of an exclamation mark. The answer is simple: Rust implements 'println' as a macro, which gets invoked in a different way.

Given that Rust is a compiled language, our example must be processed before it can be run from the command line:

tamhan@tamhan-thinkpad:~/rustspace$ rustc firsttest.rs 
tamhan@tamhan-thinkpad:~/rustspace$ ./firsttest 
Hello World!

Advanced decay

Describing a complete programming language, such as Rust, in the limited space we have available here is impossible. So let's start by formally pointing you to Mozilla Research's comprehensive documentation. One feature which is sure to impress C programmers involves the use of the 'match' command: in addition to direct comparisons, it also enables the use of range operators to greatly simplify the design of advanced programs:

fn main() { 
    let number = 5; 
    println!("Working on {}", number); 
    match number { 
        1 => println!("One!"), 
        2 | 3 | 5 | 7 => println!("Prime"), 
        _ => println!("A number"), 
    } 
} 

Garbage-at-hand

Classic garbage collection has its weaknesses: most implementations bring the program to a screeching halt from time to time. To get around that Rust uses a set of so-called 'zero-cost abstractions' to emulate a similar behaviour in a less annoying fashion.

In principle, every resource is created with an owner in a fashion similar to Qt's parent-child subsystem. However, a feature called 'borrowing' enables the programmer to transfer ownership between resources temporarily, thereby passing them around the system. 

Unfortunately, a complete discussion of the possibilities of Rust's memory manager would break the limits of this article – let it suffice to declare that Rust provides a very unorthodox, but workable form of memory management.

Create a new project

 Similarities to NPM are purely coincidental...

 Similarities to NPM are purely coincidental...

While C and C++ code can be broken down into libraries, doing so is an annoying and somewhat uncomfortable task. Furthermore, making sure that all the required libraries are where they are needed is something even seasoned developers like to avoid.

The JavaScript community has long solved this problem via products such as NPM. Projects are described via a project structure file, which – among other things – contains references to libraries and other elements needed during the actual compilation run. 

In the case of Rust, a package manager called Cargo does a similar job. Creating a new project can be accomplished through the use of the 'cargo new' command in a fashion similar to the following:

tamhan@tamhan-thinkpad:~/rustspace$ cargo new futuresample1 --bin 
     Created binary (application) `futuresample1` project 
tamhan@tamhan-thinkpad:~/rustspace$

When the creation process is complete, a folder structure similar to the one shown in the picture at the bottom of this page will be generated.

.toml files act as 'controllers' – in the case of our newly-generated project, the file contains the following structure:

[package] 
name = "futuresample1" 
version = "0.1.0" 
authors = ["tamhan"] 
[dependencies]

Similarities to the .ini files of lore are not purely coincidential: in a fashion not dissimilar to NPM, the ancient configuration file format is also used to describe the configuration files used for Rust projects. The '[dependencies]' block is of special interest for us – it contains a list of all external libraries, which need to be present for the compilation to succeed.

Add a packet

Creating a web server by hand is an annoying job best left to masochists. We will, instead, opt for a framework. Sadly, finding the right one is not easy – as visiting AWWY's list of web development frameworks reveals, there are a lot of candidates.

We will pick Rocket, if only because it seems to be quite popular and has seen an update released in May 2018. Sadly, Rocket's developers tend to take a liking to newly introduced language features, which is why frequent updating of your Rust installation using the following commands is required:

tamhan@tamhan-thinkpad:~/rustspace/futuresample1$ rustup update && cargo update

The next step largely is a question of taste. Most libraries come with pre-provisioned starter projects, which developers can simply siphon from GitHub. Doing so for your 'prime' library is not necessarily a bad idea – although once more than one library is involved, a manual approach tends to be more fruitful.

Next, open the .toml file, then modify the 'dependencies' section as per the following in order to include a recent version of the Rocket framework:

[dependencies] 
rocket = "0.3.6" 
rocket_codegen = "0.3.6"

Rocket is unique in that it requires the inclusion of a total of two packages: in addition to the main framework, a separate code generator file is also required. Either way, our version includes a specific version of the two libraries – Cargo can also accept wildcards, which enable the program to 'pick its poison' without any help from us.

With that out of the way, one problem remains: enter 'cargo run' in the folder containing the .toml file in order to perform an assisted compile, which will – among other things – download the relevant code libraries from the repository and compile the whole enchilada for you.

Next page: scaffolding and in-depth analysis