Learn Rust, Elixir and JavaScript in 10 mins and build a Guess game!

Learn Rust, Elixir and JavaScript in 10 mins and build a Guess game!

ยท

12 min read

Rust and Elixir are rated highly among the most loved programming languages. And in fact, are gaining a lot of attention recently. Safety and Performance boost of Rust, while Elixir's immutability and pattern matching baked-in would blow away any intermediate dev mind ๐Ÿคญ.

The goal of the article is to teach you both languages plus JavaScript Node in 10mins. If you by chance read to the end of this article, you would have built a guessing game in all three languages.

Who are the target audience ๐Ÿ•?: This article is targeted at complete beginners to Rust and Elixir but not Javascript. The article requires some knowledge of javascript, its syntaxes and the terminal.

What this article is not ๐Ÿ˜ฃ: This article is not a detailed explanation of the difference, and similarities between these three languages or why you should favor one over the other.

What Does Each Feel Like?

Rust and JavaScript feel like a family but with their differences. No wonder JS devs love Rust and any dev who gives the language a try.

Give me a moment to talk about Elixir - I have a special attachment to this one ๐Ÿ˜Ž. Elixir is the functional dreamland of JS.

JS has this huge functional programming side of it. This is where concepts like currying and function-composition, pipe-ing, side-effects, immutability, Futures over Promises etc are discussed with all sorts of brilliant code to paint this experience in JavaScript. Elixir has all these concepts baked in seamlessly in such a way you don't think about them...you ride in and use them.

via GIPHY

Variables

Rust and JS: Similar to JavaScript, Rust shares the same keywords - let and const - for declaring a variable.

  let name = "Kelvinsekx";
  let language = "English";
  const AGE: i32 = 34;
  const CITIES: [&str; 2] = ["lagos", "new york"];

All the Rust codes above are valid Javascript codes ๐Ÿ˜ (except the type in const -: i32, :[&str; 2]. Isn't that lovely?

Note ๐Ÿ™‹โ€โ™€๏ธ: Although the Rust codes above feel so much like JS, some rules apply to Rust's const.

3 Ways Rust Constant Differ from JS

  1. Variables in the const keyword are called constants and their names must be in capital letters.

    e.g. const AGE and const CITIES are valid constants. const name, const Name, const Cities, const CitiEs are not. Everything must be written in CAPITAL.

  2. Values passed to the variable are not mutable. When an array or tuple is passed to a constant, you can not mutate them ever unlike in Javascript.

  3. Rust is statically typed just like TypeScript. For constants, Rust doesn't take the type inference but instead mandates types be explicitly written.

     // this is valid โœ…
     let name = "Kelvinsekx";
    
     // this is invalid โŽ
     // because no type is explicitly added
     const NAME = "Kelvinsekx";
    
     // this is valid โœ…
     const NAME: &str = "Kelvinsekx"
    

Elixir Variable: Elixir doesn't use a keyword before a variable name - Just name it. All the variables below are valid in Elixir. No const, var or let keyword before them ๐Ÿฅฃ... hum yummy.

  name = "Kelvinsekx";
  language = "English";
  age = 34;
  cities = ["lagos", "new york"];

via GIPHY

Cheap Side Effect

print to a new line: Printing contents or data to the console has forever been the debugging mantra for JS devs - the almighty console.log.

I call console.log the cheap side effect. It is used to print a value to the console and immediately exists with a new line.

Although printing to the console is popular among JS dev, it is noteworthy to say the console only exists in the browser. In the terminal, the console is regarded as STDOUT - standard output.

How to Print to the Terminal

  • Javascript console: This is a multi-purpose function. It takes any data type. eg console.log(34), console.log("thirty-five"), console.log([35]). Other languages aren't this lenient with printing all sorts of data types.

  • Rust println! : The println! is a macro and not a function because it does some meta-programming behind the scene. It is indeed not right to call it a function ๐Ÿ˜ฅ.

    That aside, you can print whatever data type but with some syntactic sugar difference.

    • Print strings with empty bracelets println!("{}", "Ibadan"),

    • print every data type aside strings with println!("{:?}", other_data_type).

      These 2 patterns are not exhaustive but let's stick to this dichotomy for now.

    fn main() {
        let name = "Kelvinsekx";
        let language = "English";
        const AGE: i32 = 34;
        const CITIES: [&str; 2] = ["lagos", "new york"];

        println!("{} {}", name, language); // Kelvinsekx English
        println!("{:?} {:?}", AGE, CITIES); // 34 ["lagos", "new york"]
    }
  • Elixir IO.puts/inspect: Just like Rust we use IO.puts for strings and IO.inspect for any other data type. When using inspect, you do not wrap the variable or data around quotes.

      defmodule Prompt do 
        def start() do
          name = "Kelvinsekx"
          language = "English"
          age = 34
          cities = ["lagos", "new york"]
    
          IO.puts("#{name} #{language}") // #{} is used for data-binding
          IO.inspect(age)
          IO.inspect(cities)
        end
      end
    

To save us some time, run all code in Replit, https://replit.com/
It is a simpler alternative to run your code instead of setting up a local dev environment yourself

You are killing it. Take a break!

via GIPHY

Mutability and Immutability

While JS is extremely loose on this concept, Rust and Elixir do not take them likely. Elixir goes as far as to enforce everything is immutable.

However, as you would guess, Rust shares the same perspective with Javascript - You can mutate variables. But there is a BIG FAT RULE, Rust must know beforehand where and when you want mutation to happen. The keyword to do this is mut .

Except you are very intentional about mutating a variable, avoid unnecessary use of mut in your Rust code.

The One Big Mutability Rule in Rust

  1. const is not mutable
    Remember from our section - 3 Ways Rust Constant Differ from JS. Number 2, it states that constants are immutable.
 fn main() {
      let mut name = "Kelvinsekx"; // notified with mut
      let mut language = "English"; // notified with mut
      const AGE: i32 = 34; // const aren't mutable
      const CITIES: [&str; 2] = ["lagos", "new york"]; // const aren't mutable

      name = "Bukunmi Aje";
      language = "French";
      println!("{} {}", name, language); // "Bukunmi Aje French"
      println!("{:?} {:?}", AGE, CITIES); // 34 ["lagos", "new york"]
  }

You will see a warning when you run this code above. Take it with a pinch of salt for now.

We Don't Mutate Here in Elixir Land

A mutation is allowed in Rust and Javascript. On the good side, Rust ensures everyone is aware of any variable that tends to change. It attains this by forcing the use of mut .

At first, this might look daunting and like an overhead. If you reread the previous paragraph but slower this time, you would appreciate Rust for this kind gesture and wonder how on earth this doesn't exist in Javascript. You might start to ask yourself rhetoric like

  • Why would anything just change and I'm not very aware about ๐Ÿ‘ฟ?

  • ๐Ÿ•ถ How do I know if a callback mutates an argument?

  • ๐Ÿค” Would this prototype method mutate this Object?

  • Is Array.map mutating my Array? Is Array.split doing the same ๐Ÿ˜ฎ?

Rust completely change the game. Hold Up ๐Ÿ‘ฎโ€โ™‚๏ธ, the game of mutability is on another level in Elixir. Elixir variables are immutable not only by default. Entirely, we have no way to mutate anything in the language. You will never have to think of it.

WE DO NOT MUTATE HERE ๐Ÿ˜

Conditions, If and Else If

Variety is the spice of life they say ๐Ÿ˜‹. One way to make this is the use of conditional statements in programming languages.

Since you are familiar with Javascript, see this code below. We would be replicating the same across Rust and Elixir.

 function main() {
      let name = "Kelvdinsekx"; 
      let language = "English";
      const AGE: number = 34; 
      const CITIES: string[] = ["lagos", "new york"];

      if(name.toLowerCase() == "kelvinsekx"){
        console.log(`${name} lives in ${CITIES[0]}. And ${AGE} years.`); // "Kelvinsekx lives in lagos" 
      }else {
        console.log(`${language} is spoken in ${CITIES[1]}`); // "English is spoken in new york" 
      }
  }

  main()

Before moving to coding, let's have a break talking about some of these languages peculiarities

Name Case Conventions

Javascript is not strict with name cases. By industry standards, Camel casing is used in the JS ecosystem as in .toLowerCase, useState.

Unlike JS, Rust standard is The snake case. It is strict because It would print an error if you do not use its casing pattern. The snake case looks like to_lowercase , use_state.

The same with JS, Elixir isn't strict with name cases. However, by industry standards Elixir use the snake case.

name with spaceRustElixirJavaScript
strictnesvery strictnot strictlose
case stylesnake_casesnake_casecamelCase
to lowercaseto_lowercaseto_lowercasetoLowerCase
precision rangeprecision_rangeprecision_rangeprecisionRange

Pascal casing is usually preferred for classes and modules in Javascript and Elixir e.g StudentsPolicies

Read more about name-casing conventions like Snake Case VS Camel Case VS Pascal Case VS Kebab Case.

Back to our simple dynamic code
Because Rust looks so much like Javascript. Have it in a gooo!!

 fn main() {
      let name = "Kelvdinsekx"; 
      let language = "English";
      const AGE: u8 = 34; 
      const CITIES: [&str; 2] = ["lagos", "new york"];

      if name.to_lowercase() == "kelvinsekx" {
        println!("{} lives in {}. And {} years", name, CITIES[0], AGE); // "Kelvinsekx lives in lagos" 
      }else {
        println!("{} is spoken in {}", language, CITIES[1]); // "English is spoken in new york" 
      }
  }

Please before I share the Elixir version of this simple program, let's talk about a very confusing part of these languages.

List, Array and Tuple

These three concepts can mean the same, be partially different or completely different. The validity of each reality depends on the angle of language you are seeing it from.

via GIPHY

A novel approach to ensure everything doesn't get completed is to compare these concepts across Elixir, Rust and JavaScript.

Peas Angle to Them

The popular take is that array, tuples and list mean the same thing especially if you are from the JS ecosystem. I have seen many JavaScript resources use tuples,arrays and lists interchangeably.

Array = Tuple = List = []

The statement isn't entirely true for a couple of reasons. The leading one is that their definitions aren't the same to start with.

  1. Tuple is a non-increasing list of items. All items are mandatory the same type.
[12, 34, 45] // โœ…
[12, "Alexis", "23 years"] // โŒ
["12", "Alexis", "23 years"] // โœ…
  1. Tuple is a list of items, increasing or not, with items being of varying types.
[12, 34, 45] // โœ…
[12, "Alexis", "23 years"] // โœ…
["12", "Alexis", "23 years"] // โœ…
  1. The list in this case is a Linked list. This is beyond our scope in this article.

JavaScript Array can be both a tuple and a string. It can take an increasing number of items with the same types or not.

Rust and Elixir use two different literals to express tuples and arrays.

Tuple

  • in Rust is expressed in round brackets, ().
    As in (12, 34, 45) , ("Alexis", "I", "Love", "You")

  • in Elixir is expressed in bracelets, {} .

    As in {12, 34, 45}, {"Alexis", "is", "beautiful"}

Array

  • Array in Rust is expressed in block brackets, []

    As in [12, 34, 45], [12, "Alexis", "23 years"]

  • Unfortunately ๐Ÿ˜Œ, Elixir does not have an array but instead a List.
    The list is expressed in block brackets, []

RustElixirJavaScript
Tuplesround brackets, ( )braclets, { }square brackets, [ ]
Arraysquare brackets, [ ]Non Existsquare brackets, [ ]
ListNon Existsquare brackets, [ ]Non Exist

Linked List is implementable in Rust and Javascript. If you want to implement one yourself, this youtube video by Code Evolution is a good place to start.

Back to code
The Elixir version of the dynamic code above is

defmodule Prompt do 
  def start() do
    name = "kelvinsekx"
    language = "English"
    age = 34
    cities = ["lagos", "new york"]

    if name == "kelvinsekx" do
      IO.puts("#{name} lives in #{hd(cities)}. And #{age} years") # "Kelvinsekx lives in lagos" 
    else
      IO.puts("#{language} is spoken in #{hd(tl(cities))}") # "English is spoken in new york" 
    end
  end
end

Prompt.start

A Simple Project: Guess Game

To reduce the lengthiness of this post, I have decided to share the snippets of these codes only and not talk deeply about them.

Other important concepts like Default Pattern-Matching in Elixir etc will be talked about in subsequent posts of mine.

defmodule Prompt do 
  def start() do
    name = 4;
    input = IO.gets("""
      Guess a number between 1 - 10
    """)
    user_input = String.to_integer(String.trim(input))

    if name == user_input do
      IO.puts("Hurray ๐Ÿ˜. Your guess #{user_input} is right")
    else
      case user_input do 
        x when x > name -> IO.puts("#{user_input} is too high")
        x -> IO.puts("#{x} is lower than the guess")
      end 
    end
  end
end

Prompt.start
fn main (){
  start()
}

fn start () {
    let name: u8 = 4;
  println!("Start your game. Input a number between 1 - 10");
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    let input = input.trim().parse().unwrap();

    if name == input {
      println!("Hurray ๐Ÿ˜. Your guess #{} is right", input);
    } else {
        if input > name{
            println!("#{} is too high", input);
        }else {
             println!("#{} is lower than the guess", input);
        }
    }
}
import readline from 'readline'

function start() {
  let name = 4;

  let input = '';
  const gets = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  })

  gets.question("Start your game. Input a number between 1 - 10\n", (text) => {
    input = text.trim()
    input = Number(input);

    if (name == input) {
      console.log(`Hurray ๐Ÿ˜. Your guess ${input} is right`);
    } else {
      if (input > name) {
       console.log(`${input} is too high`);
      } else {
       console.log(`${input} is lower than the guess`);
      }
    }
    gets.close()
  });
}

start()

wow ๐Ÿ˜ณ, who would have believed you read this far? You deserve all the GIFs in this world.

via GIPHY

I feel honored I could be of help. Rust, Elixir and JavaScript have a lot more in common than we talk about. Hopefully, with this article and more to come, you find them far easier.

Bye!

Oops before I leave, if I catch your fancy, find me everywhere as kelvinsekx.

via GIPHY

ย