Rust in the Browser for JavaScripters: New Frontiers, New Possibilities

Rust in the Browser for JavaScripters: New Frontiers, New Possibilities

Rust in the Browser for JavaScripters: Thanks to wasm, Rust can reach the platform with the largest reach: the browser. JavaScripters can unlock high-performance concurrency and graphics thanks to Rust.

Thanks to wasm, Rust can reach the platform with the largest reach: the browser. We’ll take a look at how thanks to the impressive language design, thoughtful compiler error messages, and great documentation, JavaScripters can unlock high-performance concurrency and graphics thanks to Rust. We’ll step through Rust/wasm/JS interop, see what it’s like to get a reference to a canvas instance, to communicate with services workers, and to pass data between all the pieces involved. We’ll take a look at what’s enabled, as well as pitfalls around the data boundaries involved, and the size of the final payload, so that it’s clear where the cost of introducing Rust is outweighed by its benefits. Finally, we’ll speculate on how the web may develop, with a Rust-core/JavaScript-surface design, combining high performance, safety, while maintaining ease-of-use.

The Rust Programming Language - Understanding Loops in Rust

The Rust Programming Language - Understanding Loops in Rust

In this Rust programming language tutorial, we'll understanding Loops in Rust. Rust currently provides three approaches to performing some kind of iterative activity. They are: loop, while and for. The infinite loop is the simplest form of loop available in Rust. Rust also has a while loop. The for loop is used to loop a particular number of times

Rust currently provides three approaches to performing some kind of iterative activity. They are: loop, while and for. Each approach has its own set of uses.

loop

The infinite loop is the simplest form of loop available in Rust. Using the keyword loop, Rust provides a way to loop indefinitely until some terminating statement is reached. Rust's infinite loops look like this:

loop {
    println!("Loop forever!");
}

while

Rust also has a while loop. It looks like this:


# #![allow(unused_variables)]
#fn main() {
let mut x = 5; // mut x: i32
let mut done = false; // mut done: bool

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}
#}

while loops are the correct choice when you’re not sure how many times you need to loop.

If you need an infinite loop, you may be tempted to write this:

while true {

However, loop is far better suited to handle this case:

loop {

Rust’s control-flow analysis treats this construct differently than a while true, since we know that it will always loop. In general, the more information we can give to the compiler, the better it can do with safety and code generation, so you should always prefer loop when you plan to loop infinitely.

for

The for loop is used to loop a particular number of times. Rust’s for loops work a bit differently than in other systems languages, however. Rust’s for loop doesn’t look like this “C-style” for loop:

for (x = 0; x < 10; x++) {
    printf( "%d\n", x );
}

Instead, it looks like this:


# #![allow(unused_variables)]
#fn main() {
for x in 0..10 {
    println!("{}", x); // x: i32
}
#}

In slightly more abstract terms,

for var in expression {
    code
}

The expression is an item that can be converted into an iterator using IntoIterator. The iterator gives back a series of elements, one element per iteration of the loop. That value is then bound to the name var, which is valid for the loop body. Once the body is over, the next value is fetched from the iterator, and we loop another time. When there are no more values, the for loop is over.

In our example, 0..10 is an expression that takes a start and an end position, and gives an iterator over those values. The upper bound is exclusive, though, so our loop will print 0 through 9, not 10.

Rust does not have the “C-style” for loop on purpose. Manually controlling each element of the loop is complicated and error prone, even for experienced C developers.

Enumerate

When you need to keep track of how many times you have already looped, you can use the .enumerate() function.

On ranges:


# #![allow(unused_variables)]
#fn main() {
for (index, value) in (5..10).enumerate() {
    println!("index = {} and value = {}", index, value);
}
#}

Outputs:

index = 0 and value = 5
index = 1 and value = 6
index = 2 and value = 7
index = 3 and value = 8
index = 4 and value = 9

Don't forget to add the parentheses around the range.

On iterators:


# #![allow(unused_variables)]
#fn main() {
let lines = "hello\nworld".lines();

for (linenumber, line) in lines.enumerate() {
    println!("{}: {}", linenumber, line);
}
#}

Outputs:

0: hello
1: world

Ending iteration early

Let’s take a look at that while loop we had earlier:


# #![allow(unused_variables)]
#fn main() {
let mut x = 5;
let mut done = false;

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}
#}

We had to keep a dedicated mut boolean variable binding, done, to know when we should exit out of the loop. Rust has two keywords to help us with modifying iteration: break and continue.

In this case, we can write the loop in a better way with break:


# #![allow(unused_variables)]
#fn main() {
let mut x = 5;

loop {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 { break; }
}
#}

We now loop forever with loop and use break to break out early. Issuing an explicit return statement will also serve to terminate the loop early.

continue is similar, but instead of ending the loop, it goes to the next iteration. This will only print the odd numbers:


# #![allow(unused_variables)]
#fn main() {
for x in 0..10 {
    if x % 2 == 0 { continue; }

    println!("{}", x);
}
#}
Loop labels

You may also encounter situations where you have nested loops and need to specify which one your break or continue statement is for. Like most other languages, Rust's break or continue apply to the innermost loop. In a situation where you would like to break or continue for one of the outer loops, you can use labels to specify which loop the break or continue statement applies to.

In the example below, we continue to the next iteration of outer loop when x is even, while we continue to the next iteration of inner loop when y is even. So it will execute the println! when both x and y are odd.


# #![allow(unused_variables)]
#fn main() {
'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // Continues the loop over `x`.
        if y % 2 == 0 { continue 'inner; } // Continues the loop over `y`.
        println!("x: {}, y: {}", x, y);
    }
}
#}

Rust for JavaScript Developers

Rust for JavaScript Developers

Rust is a multi-paradigm system programming language focused on safety, especially safe concurrency. In this post, I am gonna present Rust from a JavaScript developer perspective doing some side-to-side comparisons. I hope it will motivate you to give it a try!

The first time I read about Rust 🦀 it didn't pique my interest. Around two years ago, I was working as a web developer, mostly using JavaScript and I thought Rust wasn't for me because it looked really difficult at that moment.

At the start of this year, I decided to start learning Rust on my own. What has changed during this time? I am still a web developer but knowing that I will be able to write a program in Rust, compile to WebAssembly and execute it in the browser has been the spark that ignited my motivation.

In this post, I am gonna present Rust from a JavaScript developer perspective doing some side-to-side comparisons. I hope it will motivate you to give it a try!

What is Rust?

The Rust programming language was created by Mozilla and its first stable version was released around 2015. It looks like this:

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

It doesn't look so scary, right? You could say it almost looks like JavaScript but that's just the hello world program and it's a bit more complicated! Before looking at some features of the language let's place Rust in the programming languages spectrum like this:

[

There is a clear distinction between programming languages:

  • Low-level: Languages like C++ that has access to memory management are considered low level and they are very fast. They are also very insecure because it's very easy to mess up with memory and bad things can happen!
  • High-level: On the other hand, languages like JavaScript don't have that granular access to memory (there is the Garbage Collector that handles everything for us) and are considered safe languages so sometimes they can be slow.

Rust can be considered both fast and safe but it doesn't come for free: there is a steep learning curve and the compilation time can be a bit high even for small examples.

Rust key features

Like any programming language, there is a lot to cover but I decided to focus on four topics that are essential to learn the language and start working on it.

Types

JavaScript is a dynamically typed language, and we can do some fun things like subtracting the number 1 to the string wat and obtain unexpected results. This is possible because the type system is not strict. In Rust, if you try to perform a simple addition of two numbers that are not of the same type you get a compilation error:

fn main() {
    let a: i32 = 42;
    let b: f64  1.0;
    println!("{}", a + b); // ERROR: a and b are not of the same type.
}

You will get a lot of errors when you start working in Rust and you will probably hate the compiler at first:

If you feel like this dog and you are constantly fighting the Rust compiler don't worry! We all have been there.

Immutability

Functional languages are very well-known for working with immutable structures. As JavaScript developers, we are not forced to work with immutability but popular libraries like Redux and Immutable.js taught us these good practices. Today we have the let and const keywords to declare mutable and immutable variables respectively.

In Rust, we are gonna use just let to declare variables, and they will be immutable by default. If we want to use mutable data we need to add the mut keyword to the declaration like this:

fn main() {
    let a = 42;
    let mut b = 1;

    a = 43; // ERROR: a is not mutable
    b = 2;
}

Ownership

In my opinion, this is the hardest concept to learn Rust because it is really different from other languages that I worked on but this is the key that makes Rust fast and safe to use!

When you assign some data to a variable it is said that the variable owns it and every piece of data can only have one owner. Let's see this in action:

fn main() {
    let x = String::from("hello"); // x owns the "hello" string
    let a = x; // At this point a owns the "hello" string and x is no longer valid
    do_something(x); // ERROR: x cannot be used anymore!
}

In Rust there is no null and undefined values, so we cannot use a variable that doesn't have a value. In the previous example when we assigned a to x we are moving the value from x to a so at this point x doesn't have a valid value. The same happens with functions:

fn main() {
    let x = String::from("hello");
    do_something(x);
    do_other_thing(x); // ERROR: x cannot be used anymore!
}

fn do_something(s: String) {
    // Do something with s
}

When we call the method do_something we are moving the value from x to s, the argument received by the function. After executing the function we return to main and x doesn't have a valid value anymore.

The previous behavior is not always desired and that's the reason that in Rust we can borrow things! If you don't want to move a value from a variable to another one use references like this:

fn main() {
    let x = String::from("hello");
    do_something(&x);
    do_other_thing(&x); // This is ok now because we are not moving the value
}

fn do_something(s: &String) {
    // Do something with s
}

When we are dealing with ownership and borrowing the Rust compiler wants us to play nice so it will warn us if you we try to do something wrong:

[

If you are confused after learning about ownership and borrowing it is ok! Your brain has started to deal with memory management and it can hurt sometimes. I recommend you watching this video to learn more about this topic.

Structs

Rust is not an object-oriented language but it has some features that can emulate some behavior present in that kind of languages. When we work with classes in JavaScript we are dealing with both data and methods in the same place. In Rust, we are gonna separate the data representation from the methods that manipulate it like this:

struct Dog {
    name: String,
    score: i32
}

impl Dog {
    fn say_something(self: &Dog) {
        println!("Hey, my name is {}... I mean WOOF!", self.name);
    }
}

fn main() {
    let dog = Dog { name: String::from("Boira"), score: 13 };
    dog.say_something();
}

The struct Dog looks pretty similar to a JavaScript object but it's not. The struct is the shape of some data that will have two named fields: name and score. Below the struct you can see an implementation block (impl for short). We can declare methods that will manipulate the data like this and notice that if we want to associate the function with that data we need to pass self as the first argument. It kinda looks like Python, doesn't it?

If we omit the self value we are declaring a method that is not associated with any particular piece of data. You can think of it as a static method in a JavaScript class.

What can I do with Rust?

The first thing you need to do is install Rust and it cannot be easier. Visit the https://rustup.rs/ web to download the official toolchain installer. It is kinda similar to the nvm project that is commonly used with JavaScript.

Then you are gonna need some libraries so don't start from scratch. In the same way as we have Node packages in JavaScript we are gonna deal with crates in Rust. Visit crates.io, the official crates registry, to know more about Rust crates.

Since Rust is very versatile there are a lot of topics where Rust can be used and the community has made a good effort to track them in different websites:

  • www.arewewebyet.org: Even if there are no frameworks as mature as Ruby on Rails you could build some stuff! I recommend taking a look at the Rocket framework if you want to do some web development. You can even create GraphQL APIs using Juniper!
  • www.arewegameyet.com: Having full control of memory management is a necessary feature to create some kind of games so Rust is a wonderful candidate! If you are interested in game development I recommend you checking the Amethyst game engine.
  • www.arewelearningyet.com: Another topic that is widely popular right now is machine learning. The Rust ecosystem isn't very complete right now and it may not be as good as Python right now to do machine learning but If you are interested in the topic check their website!

Finally, if you are doing web development you are lucky! You can create programs, compile them and use it all together with your existing JavaScript code. The technology that made this possible is WebAssembly and it can be used right now in all modern browsers.

If you want to try it I recommend you to read the official Rust and WebAssembly book.

Conclusion

Rust is a really cool language to learn and you could build a lot of things with it! If you are a web developer like me you will find the whole WebAssembly topic very interesting and I hope I can write future posts about it.

If you want to start working with Rust I recommend you checking the official book and try to write some existing JavaScript programs with Rust. As a lot of things practice is the key!

Rust in the Browser for JavaScripters: New Frontiers, New Possibilities

Rust in the Browser for JavaScripters: New Frontiers, New Possibilities

Thanks to wasm, Rust can reach the platform with the largest reach: the browser. We’ll take a look at how thanks to the impressive language design, thoughtful compiler error messages, and great documentation, JavaScripters can unlock high-performance concurrency and graphics thanks to Rust. We’ll step through Rust/wasm/JS interop, see what it’s like to get a reference to a canvas instance, to communicate with services workers, and to pass data between all the pieces involved. We’ll take a look at what’s enabled, as well as pitfalls around the data boundaries involved, and the size of the final payload, so that it’s clear where the cost of introducing Rust is outweighed by its benefits. Finally, we’ll speculate on how the web may develop, with a Rust-core/JavaScript-surface design, combining high performance, safety, while maintaining ease-of-use.

Why even though Rust requires more effort, it’s approachable for JavaScript developers. How Rust combines with service workers and WebGL open new possibilities? What does Rust/JS interop look like, and what are the steps involved?

There’s a reasonable chance that the future of WebUI will have Rust at its core.