DEV Community

Cover image for Elixir and Javascript syntax comparison
Maartz
Maartz

Posted on

Elixir and Javascript syntax comparison

On a daily basis at work I use 2 languages. Java and Javascript.
Doing Javascript everyday and learning Elixir, I recognize some patterns. Let's recap.

Nobody ignores in the web dev planet the features that ES6 ships to the Javascript language, especially the functional ones.

Summary

  1. Objects vs Modules
  2. Method chaining vs Pipe Operator
  3. Destructuring vs Pattern Matching
  4. High Order Functions

Objects vs Modules

With ES6, the class keyword and all the OO ceremony come in Javascript.
In Elixir, as a functional language, it doesn't support the idea of Object, instead, we've Modules, which can be seen as bucket or namespace for functions.

Example of an Object in Javascript:

const Circle = {
  PI: Math.PI, // Math.PI is a constant
  area: r => Circle.PI * (r ** 2),
  circumference: r => Circle.PI * (r * 2)
};

Circle.area(2) // 12.56...
Enter fullscreen mode Exit fullscreen mode

Same in Elixir:

defmodule Circle do
  @pi :math.pi() # Here we define a module constant

  def area(r), do: @pi * (r * r)
  def circumference(r), do: 2 * @pi * r
end

Circle.circumference(5) # 31.41..
Enter fullscreen mode Exit fullscreen mode

So in my opinion, I've gained some good habits from FP, like writing little functions, which are responsible of a tiny modification of the input new output based on the one passed, and the modification asked. So that's what we call a reducer.
And this, let us build very complex data transitioning with ease, so it leads us naturally to the next step: Method Chaining vs Pipe Operator.


A bit of background: Erlang and Elixir

In a precedent example, I've used :math.pi() which is not an Elixir module, here's why.
Unlike Javascript, Elixir does not have a Math module, instead, it leverage the Erlang standard library. In fact, Elixir is built on top of Erlang. Furthermore, Elixir and Erlang are interoperable. Which means we can use the huge ecosystem of Erlang libraries in our Elixir code. That's pretty neat.
So to call an Erlang module in Elixir, we just have to type the following:

:erlang_module.erlang_function()
:math.pi()
:crypto.hash(:md5, data) # To use crypto library and hash with MD5
Enter fullscreen mode Exit fullscreen mode

Method Chaining vs Pipe Operator

So here we are going to take a real-world example, squaring a list of numbers and reducing the value to a single one. So we can use in both languages the map and reduce functions.

Javascript

const numbers = [1,2,3,4,5]\
let sumOfSquares = list
  .map(num => num * num)
  .reduce((num, acc) => acc + num)
Enter fullscreen mode Exit fullscreen mode

In Elixir, we will use the pipe operator

list_of_numbers = [1,2,3,4,5]
sum_of_squares =
  list_of_numbers
  |> Enum.map(&(&1 * &1))
  |> Enum.reduce(&(&1 + &2))
Enter fullscreen mode Exit fullscreen mode

Two things here which are Elixir specific, first the |> aka pipe operator and second, this exotic piece of syntax '&(&1)'.

So the pipe operator let us pass the data from a function call to another in a Unix shell fashion. But, as uncle Ben told us, with great power comes great responsibility, well ... kidding, here there's just one rule, your first function parameter should be the output of the previous function. That's all. So map in both Javascript and Elixir returns an Array or a List (same thing but different naming).

To truly leverage this pipe operator, you must think in function composition. Here's an example for a simple scrapper that I wrote.
I needed to perform a call to a specific URL, handle the 301 HTTP status, get the correct URL and then make a new call to the properly formatted URL.

def get_url(ean) do
    HTTPoison.start()
    url =
      "#{@url}-#{ean}" # Module constant here
      |> HTTPoison.get!() # Call to another Module function
      |> get_html() # Module function
      |> get_title() # Module function
      |> List.to_string() # List Module function call
      |> split() # Module function
  end
Enter fullscreen mode Exit fullscreen mode

So this pipe operator avoid one thing, function call hell like this:

function3(function2(function1(data))) // works but we loose readability
Enter fullscreen mode Exit fullscreen mode

The pipe operator put the data where it should be. At the top of the attention, after all, that's what we are processing.

As far as I recall, it seems that the pipe operator is in a proposal stage at the TC39. Anyway, it's also available in ReasonML, so in React-Reason.

And what if I told that we can extract data of a variable easily by just describing what we want ?

Destructuring vs Pattern Matching

In Elixir, we say x = 1, you probably think that x is equal to 1. But there's a subtle difference, we do not say this is equality, we say its a match. The value behind x is 1 because we have bind the free variable named x to match the value of 1. So the = sign is called the match operator and not equal.

Thinks of this as a comparison between the Rhs and the Lhs. See how we can leverage this.

Taking MDN docs, destructuring is:

The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.

So:

let a, b, rest;
[a, b, ...rest] = [10, 20, 30, 40, 50]; // ... or spread operator
a // 10
b // 20
rest // [30, 40, 50]
Enter fullscreen mode Exit fullscreen mode

In Elixir:

list = [1,2,3,4,5]
a, b = list
** (SyntaxError) iex:2: syntax error before: ','
Enter fullscreen mode Exit fullscreen mode

Oh, it seems that it doesn't work like in Javascript... So here, list is a List type. And in Elixir, a list is a made of a head and a tail like this [head | tail] ( the pipe here is called the cons operator).
Thus, we can write a list like this [1 | [ 2 | [ 3 ]]].
Lets do this in the Elixir fashion.

list = [1,2,3,4,5]
[a|b] = list
a # 1
b # [2,3,4,5]

# One more time
[a, b, c|d] = list
a # 1
b # 2
c # 3
d # [4,5]
Enter fullscreen mode Exit fullscreen mode

In Javascript, destructuring is really great, especially in function parameters.

Like in this React component, instead of calling props.title, props.imageUrl, etc.
I choose to destructure the props parameter and cherry-pick the values I want to get from.

render() {
  return (
   <div className="directory-menu">
    {
     this.state.sections.map(({title, imageUrl, id, size}) => (
      <MenuItem key={id} title={title} imageUrl={imageUrl} size={size} />
     ))
    }
   </div>
  );
 }
Enter fullscreen mode Exit fullscreen mode

As I did in this Elixir snippet:

def draw_image(
  %Identicon.Image{color: color, pixel_map: pixel_map})
  do
    image = :egd.create(250, 250)
    fill = :egd.color(color)

    Enum.each pixel_map, fn({start, stop})  ->
      :egd.filledRectangle(image, start, stop, fill)
    end

    :egd.render(image)
  end
Enter fullscreen mode Exit fullscreen mode

To extract the values from the Identicon.Image struct, I pattern matched on the fields of the passed struct in the function parameter. But what if we can call functions in function parameters?

High Order Function

In Elixir, function are first-class citizens, so a function can take a function as a parameter and/or return a function.

So let's get a non-trivial example!

// In ES6 style
const multiplyAll = array => times => array.map(
  item => item * times
);

// In ES5 style
var multiplyAll = function multiplyAll(array) {
  return function (times) {
    return array.map(function (item) {
      return item * times;
    });
  };
};

multiplyAll([2,7,3,60])(2) // [4, 14, 6, 120]
Enter fullscreen mode Exit fullscreen mode

This what we call 🍛 🙌 CURRYFICATION 🍛 🙌!

We can see in ES5 style that we have a function, which returns a function, which uses a method with a lambda AKA anonymous...function!

Yo Dawg, I've heard you like functions so we put functions in your functions which returns functions in the function body... 🤔

In fact it helps a lot. See, we can leverage this style to prevent side effects, and aims pure functions.

In Elixir, we can do this, this way:

# Here we declare a lambda called run_query
run_query =
  fn query_def ->
    Process.sleep(2000)    ①  
    "#{query_def} result"
  end

# Here another lambda with the previous one inside.
async_query =
  fn query_def ->
    spawn(fn -> IO.puts(run_query.(query_def)) end)
  end

# And finally, we use this lambda in another function call
Enum.each(1..5, &async_query.("query #{&1}"))

# Naively we can achieve this this way
add = fn x ->
  fn y -> x + y end
end

add.(1).(3) # 4
Enter fullscreen mode Exit fullscreen mode

This ends the Javascript vs Elixir article, the main goal is not to make a real comparison between the languages but much more leverage the strength of one language to write better code.

As I said earlier, since I've begun my Elixir journey, I realize how I can leverage Elixir's idioms and philosophy to write better Javascript, and vice-versa.

Kudos to you if you have reach the end of this.

Top comments (0)