Rust programming language and how to execute rust code using Dockerfile
This contains information about rust programming language, tools, some limitations and comparison with C++. Also, about how you can run rust code inside a container (using docker).
What is Rust Programming Language?
Rust is a high-level programming language that emphasizes performance and parallel programming. Other than this, it enforces memory safety (such as dangling pointers and buffer overflow) — all references point to valid memory. Rust programming language is popular for systems programming and also has high-level features such as functional programming constructs.
In other words, Rust is used for three purposes in programming: safety, performance and memory management. According to the Stack Overflow Developer Survey 2022 conducted among over 80,000 developers, Rust is the most beloved programming language and tops Stack Overflow Survey 2022 for the 7th year. Rust was first developed by Mozilla Research. It grew out of a personal project and was officially announced in 2010.
Rust is also known for its unique memory safety model, which eliminates the risk of many common programming errors and this is achieved through the use of ownership and borrowing. Rust has two modes of writing codes ::
- Safe Rust → It imposes additional restrictions on programmer such as object ownership management just to ensure code works properly.
- Unsafe Rust → It gives programmer more autonomy and code might break. This mode unlocks more options but, need to take care to ensure code is safe and to do so, programmer can wrap it in higher-level abstractions which guarantee that all uses of abstraction are safe.
Concurrency and how Rust handles it.
Concurrency is all about multiple tasks which start, run and complete in overlapping time periods (no specific order). For example, in JavaScript, you can avoid blocking tasks on a single thread using event loops. There are three main types of concurrent computing: threading, asynchrony and preemptive multitasking. Each method has a special precaution which must be taken to prevent race conditions, where multiple threads or processes access the same shared data in memory (in improper order).
Rust makes it easier to write concurrent programs by preventing data races at compile time. A data race occurs when at least two different instructions from different threads are trying to access the same memory location simultaneously, while at least one of them is trying to write something and there is no synchronization that could set any particular order.
In Rust, data races are detected. Programmer can use channels to pass values back and forth, the memory to store these values isn’t shared. But maybe you want to share memory between your threads to reduce memory usage and for this, mutex objects are used in Rust. A mutex object can obtain a value that one thread can take ownership of at any point in time. Also, programmer can create 1:1 threads. Rust doesn’t have bundling threads feature but, can create a thread and run a series of tasks on that thread. Rust can check if we are performing any incorrect operations on objects and inform us at compile time. Other languages employ synchronization methods but, they are not related to objects they refer to.
Why to learn Rust Programming Language?
Rust is an advanced programming language that is beneficial to build tech applications. Some of the reasons to learn rust ::
- The old codes in Rust are compatible with newer versions of language.
- Easy scalability, concurrency and suitable for building heavy applications to meet the increasing tech demands in modern world.
- Rust has an asynchronous processing model that allows developers to create and run independent functions, which can be collaborated later.
Rust tools
- Cargo → Rust’s official package manager and build tool. It is used to manage Rust projects, including dependencies, building, testing and packaging.
- Rustup → A command line tool used to manage Rust installations on your system. It can be used to install new versions of Rust and switch between different Rust versions.
- Rustfmt → Automatically formats Rust Code to conform to Rust community’s style guidelines. It can ensure that code is consistent with community’s best practices.
Rust vs C++
As we know, Rust is built to focus majorly on safety and performance, especially safe concurrency whereas C++ is an object oriented programming language, also known as “C with Classes”, provides amazing performance and we can build super-fast applications because of its rich library STL (Standard Template Library).
Rust is similar to C++ but, there are several parameters in which both differ.
- Pointers & Addresses
A pointer is an object that stores memory address of another object. C++ provides unique_ptr which acts like smart pointer whereas standard libraries of Rust provides many smart pointers. - Package Management
As discussed earlier, Rust has an official package manager known as Cargo whereas C++ has some package managers such as Conan. Cargo is much easier to use than Conan. - Support for Game Development
C++ is mostly used for game development and most games in market are built using C++. On other hand, Rust also provides gaming platform and have powerful frameworks. We can develop games in Rust but, it will take more time compared to C++. Hence, C++ is better choice than Rust. - Compile Time
Build time for C++ and Rust is almost same and it completely depend on number of templates implemented. Generally, C++ performs better when it comes to compiling time. Rust compiler is user friendly and provided tools for error messages as well.
Rust is used in Augmented Reality, Virtual Reality and IoT applications in which C++ failed. Rust is also better in device-based development and works perfectly for writing codes such as kernels of operating systems, microcontroller devices, etc.
But in some areas C++ is the boss, for example; game development, compilation time, STL template and existing code.
Limitations while programming in Rust
- Developing code is not as fast as compared to other languages like Python as developers are not used to working with languages where errors in code are detected at compile time and it may be annoying to get many error messages.
- It’s usually considered harder to write code that can’t rely on garbage collection.
Rust code and how to run it using Dockerfile
Now, lets understand how to create rust code and build it on Docker.
To run and execute docker commands, I’ve used AWS cloud Linux instance on which docker is installed and is in running state. Before going forward, lets understand docker and its related terminologies in short ::
Docker and containers ::
Docker is a container management tool. It is an application build and deployment tool. It is based on the idea of that you can package your code with dependencies into a deployable unit called a container. Docker was develop by Solomon Hykes in 2013, and main motive was for shipping purpose. Hence, Docker is an open platform for developing and running applications.
A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.
Containers are a form of operating system virtualization. A single container might be used to run anything from a small microservice or software process to a larger application. Inside a container are all the necessary executables, binary code, libraries, and configuration files.
Steps ::
Step 1 -> Check Docker service
Check whether the docker service is running on your system or not using “systemctl status docker”
Step 2 -> Create necessary files
Create a directory and store all necessary files there.
Necessary files are ::
1. Rust code → .rs extension file
2. Cargo file → .toml extension file
3. Dockerfile
(I’ve explain each file in further steps)
In my case, I’ve create a directory named “test_Rust” with the respective files ::
Step 3 -> Rust code
Create rust code.
Here, I’ve created the recursive code for calculating factorial of 5.
Rust code file name is “main_file.rs”
Explanation ::
- fn main() → entry point for the program. fn means function or function pointer.
- println!() → macro that writes string to console. “!” indicates it a macro and not function.
- fact() → recursive (reusable) code. Recursive code uses internal stack to implement Last-in-first-out principle.
Step 4 -> Cargo file
Create Cargo file.
As discussed, cargo is package manager for rust. Therefore, rust code is executed using “cargo run”
Here, I’ve created Cargo.toml file but why?
Well, Cargo.toml is a configuration file for rust package manager and used to specify dependencies. It includes information about package; name and version.
Step 5 -> Dockerfile
Create a Dockerfile
Dockerfile is one way to create container. For this file, we need to specify base image (an image is template that contains set of instructions/dependencies for creating a container), necessary dependencies and command to execute after launching docker.
In the above code,
- FROM rust:latest
FROM is an instruction that specifies from which you are building and rust: latest means the base image name with version. - WORDIR .
WORDIR means the working directory for container. In other words, this instruction is used to tell container where are the required files stored for further operations.
“.” with this command represents current directory.
In my case, after this command is executed, docker will use the current directory. - COPY . .
COPY instruction is used to copy all the files from your local directory to docker container. Syntax :: COPY <to_be_copied> <destination_path>
“. .” represents all files from current directory and docker container repository respectively.
(In this case, I’ve copied rust file and cargo file) - RUN
This instruction will execute the given/any command on top of specified image. In this case, I’ve build the rust application using RUN instruction. - CMD
This instruction executes command when the docker starts. After executing this instruction, output will be available on your terminal/screen. Also, it can take multiple output parameters/values (just like the List in Python language)
Step 6 -> Build the Dockerfile
Build and execute Dockerfile
In previous step, Docker file is created and now we need to build the container. It is done using the following command ::
Let’s understand the command,
build → used to create a container
-t → an option used to specify container name
. → used to point where the Dockerfile is located (In my case, its current directory)
When this command is executed, all the instructions inside Dockerfile will be executed one after the other and a container will be created which hold the output of Rust code.
Step 7-> Output
Run the container (get output)
Now that the container is created, we just need to “docker run” command to get the rust code output. docker run command will run the container from image and also the commands inside it.
In the above command, “i” and “t” option means interactive and terminal respectively.
Conclusion
Rust has great performance and tooling. If you need a solution with a greater safety than C/C++ then, Rust is a good choice. Companies like Amazon or Figma have already used Rust in their development work.
Happy Learning…
Thank You…