Elixir Cheatsheet for Node.js Developers
Table of Contents
Hello World
Elixir
# hello.exs
defmodule Greeter do
def greet(name) do
message = "Hello, " <> name <> "!"
IO.puts message
end
end
Greeter.greet("world") JavaScript
// hello.js
console.log("Hello, world!");
Variables
Elixir
x = 1
JavaScript
let x = 1;
Nota bene: Elixir variables are immutable. Once assigned, they cannot be changed only reassigned.
N.B.2: the elixir = operator is used for assignment, but it is the match operator. Check pattern matching docs for a deep dive or take a quick look you sexy beast.
Types
Primitive Types
1 # integer
0x1F # integer -> no JS equivalent
1.0 # float
true # boolean
:atom # atom / symbol -> no JS equivalent
"elixir" # string
[1, 2, 3] # list
{1, 2, 3} # tuple
%{a: 1} # map -> Object
%Person{name: "John Doe", age: 30} # struct -> Interface
def function() do ... end # function Strings
Elixir
"elixir" # "elixir"
"elixir" <> " " <> "rocks" # "elixir rocks"
~s(elixir \x26 #{"inter" <> "polation"}) # "elixir & interpolation"
~S(elixir \x26 #{"inter" <> "polation"}) # "elixir \\x26 #{"inter" <> "polation"}" JavaScript
"JavaScript" // string
"JavaScript" + " " + "rocks" // "JavaScript rocks"
`JavaScript ${"inter" + "polation"}` // "JavaScript interpolation"
Maps
Elixir
address = %{city: "London", country: "UK"}
address[:city] # "London"
address.country # "UK" JavaScript
let address = {city: "London", country: "UK"};
address.city // "London"
address["country"] // "UK" Lists
Elixir
[1, 2, 3] # list
[1 | [2 | [3 | []]]] # list
[1, 2, 3] ++ [4, 5, 6] # [1, 2, 3, 4, 5, 6]
[1, 2, 3] -- [2] # [1, 3]
[1, 2, 3] -- [2, 3] # [1]
[1, 2, 3] -- [2, 3, 4] # [1] JavaScript
[1, 2, 3] // list
[1, ...[2, ...[3, ...[]]]] // list
[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].filter(x => x !== 2) // [1, 3]
[1, 2, 3].filter(x => x !== 2 && x !== 3) // [1]
[1, 2, 3].filter(x => x !== 2 && x !== 3 && x !== 4) // [1] Nota bene: Elixir stores lists and tuples very differently in memory. If you want performant code: look it up honey.
head and tail
The [head | tail] syntax provides functionality similar to destructuring lists in JavaScript.
Elixir
[head | tail] = [1, 2, 3]
head # 1
tail # [2, 3]
[first_element | _] = ['banana', 'apple', 'orange']
first_element # 'banana'
[_first | rest] = ['brick', 'mortar', 'stone'] # _first is unused variable
rest # ['mortar', 'stone'] JavaScript
let [head, ...tail] = [1, 2, 3];
head // 1
tail // [2, 3]
Nota bene: [head | tail] requires a variable name for ‘head’ and ‘tail’. In elixir ’_’ is a valid variable name and it is used to signify ignored/unused values. It is either the name of a variable [first_element | _] or a prefix for a variable name [_first | rest].
Touples
Elixir
{1, 2, 3} # tuple
{1, 2, 3} ++ {4, 5, 6} # {1, 2, 3, 4, 5, 6}
{1, 2, 3} -- {2} # {1, 3}
{1, 2, 3} -- {2, 3} # {1}
{1, 2, 3} -- {2, 3, 4} # {1}
JavaScript
[1, 2, 3] // tuple
[1, ...[2, ...[3, ...[]]]] // tuple
[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].filter(x => x !== 2) // [1, 3]
[1, 2, 3].filter(x => x !== 2 && x !== 3) // [1]
[1, 2, 3].filter(x => x !== 2 && x !== 3 && x !== 4) // [1] Functions
Elixir
def greet(name) do # do/end syntax
"Hello, " <> name <> "!"
end
greet("world") # "Hello, world!"
def greet2(name), do: "Hello, " <> name <> "!" # keyword syntax
greet2("world") # "Hello, world!" JavaScript
function greet(name) {
return "Hello, " + name + "!";
}
greet("world") // "Hello, world!"
Anonymous Functions
Elixir
fn (name) -> "Hello, " <> name <> "!" end # arrow syntax
fn (name), do: "Hello, " <> name <> "!" # keyword syntax
fn (name) do
"Hello, " <> name <> "!"
end
my_greet = fn (name) -> "Hello, " <> name <> "!" end # assign anonymous function to variable
my_greet.("world") # "Hello, world!" JavaScript
let myGreet = (name => "Hello, " + name + "!")
myGreet("world") // "Hello, world!"
Sigils
~r{regexp} # regular expression
~r"hello"
iex> ~s(string with escape codes \x26 stuff) # string with codes
"string with escape codes & stuff"
iex> ~S(string without escape codes \x26 stuff) # string without codes
"string without escape codes \\x26 stuff"
~c{charlist} # charlist
~w{words} # word list Control Flow
if/unless
Elixir
if true do
"true"
else
"false"
end
unless true do
"You may never see me"
end JavaScript
if (true) {
"true";
} else {
"false";
}
if (!true) {
"You may never see me";
} Since in Elixir everything is a function if/unless can be used as a JS ternary operator.
Elixir
lunch = if hungry do
"pizza"
else
"salad"
end
dress = unless cold, do: "shorts", else: "pants" JavaScript
let lunch = hungry ? "pizza" : "salad";
let dress = !cold ? "shorts" : "pants";
switch/case
Elixir
case {1, 2, 3} do
{4, 5, 6} -> "nope"
{1, 2, 3} -> "yep"
end
JavaScript
switch ([1, 2, 3]) {
case [4, 5, 6]:
"nope";
case [1, 2, 3]:
"yep";
} cond
Elixir
cond do
2 + 2 == 5 ->
"This will never be true"
2 * 2 == 3 ->
"Nor this"
1 + 1 == 2 ->
"But this will"
end JavaScript
if (2 + 2 === 5) {
"This will never be true";
} else if (2 * 2 === 3) {
"Nor this";
} else if (1 + 1 === 2) {
"But this will";
}
Pattern Matching
keep scrolling for black magic [1]
Modules
Elixir
require Redux # compiles a module
import Redux # compiles, and you can use without the `Redux.` prefix // adds functions to the current scope
use Redux # compiles, and runs Redux.__using__/1
use Redux, async: true
import Redux, only: [duplicate: 2]
import Redux, only: :functions
import Redux, only: :macros
import Foo.{Bar, Baz}
defmodule Foo do # defines a module
def Bar, do: "Bar"
end JavaScript
const Redux = require('redux'); // compiles a module
import Redux from 'redux'; // compiles, and you can use without the `Redux.` prefix // adds functions to the current scope
import { Bar, Baz } from Foo;
Structs
defmodule Person do
defstruct name: "John Doe", age: 30 # defines a Person struct with default values
end