Killer Elixir-Tips
Last updated
Last updated
Elixir Tips and Tricks from the Experience of Development. Each part consists of 10 Unique Tips and Tricks with a clear explanation with live examples and outputs. These tips will speed up your development and save you time in typing code as well.
You can read specific parts with following links...
All Photos by Form on Unsplash
Checkout some cherry picked tips from the all Parts
Copy the content into a file and save the file as .iex.exs
in your ~
home directory and see the magic. You can also download the file HERE
Each x
sigil calls its respective sigil_x
definition
Defining Custom Sigils
usage
Load the module into iex
Define Custom Error
Usage
Define a Protocol
A Protocol is a way to dispatch to a particular implementation of a function based on the type of the parameter. The macros defprotocol
and defimpl
are used to define Protocols and Protocol implementations respectively for different types in the following example.
Usage
Load the code into iex
and execute
There is no ternary operator like true ? "yes" : "no"
. So, the following is suggested.
When using pipelines, sometimes we break the pipeline for or
operation. For example:
Indeed, ||
is only a shortcut for Kernel.||
. We can use Kernel.||
in the pipeline instead to avoid breaking the pipeline.
The code above will be:
This above tip is from qhwa
Code grouping stands for something great. It shows you how your code is grouped when you write multiple lines of code in single line with out using braces. It will be more clear with the following example.
If you want to see how this line of code is grouped into, you can check in the following format..
So, by using the quote
and Macro.to_string
you can see how our code was grouped into.
This tip came out in discussion with the creator of Ecto MichalMuskala in the Elixir forum.
These replaces the nested complicated conditions. These are my best friends in the situations dealing with more complex comparisons. Trust me you gonna love this.
The ||
operator always returns the first expression which is true. Elixir doesn’t care about the remaining expressions, and won’t evaluate them after a match has been found.
||
Here if you observe the first expression is false next nil
is also false in elixir next :blackode
which evaluates to true and its value is returned immediately with out evaluating the :elixir
and :jose
. Similarly if all the statements evaluates to false
the last expression is returned.
&&
This &&
returns the second expression if the first expression is true
or else it returns the first expression with out evaluating the second expression. In the above examples the last one is the situation where we encounter to use the &&
operator.
I have self experience with this. When I was a novice in elixir, I just compared "5" > 4
unknowingly by an accident and to my surprise it returned with true
.
In Elixir every term can compare with every other term. So one has to be careful in comparisons.
Order of Comparison
number < atom < reference < fun < port < pid < tuple < map < list < bitstring (binary)
When I see this first time, I said to my self “Elixir is Crazy”. This tip really saves time and it resembles your smartness. In Elixir every operator is a macro. So, we can use them as lambda functions.
This is my recent discovery. I always encounter a situation like converting "$34.56"
which is a string and I suppose do arithmetic operations. I usually do something like this before binary pattern matching..
Tip Approach
This tip makes my day easy. I recently used this is in one of my projects.
Before I let you to use this tip, I just want to remind you that :atoms are not garbage collected. Atom keys are great! If you have a defined atoms, you are in no danger. What you should not do is converting user supplied input into atoms without sanitizing them first because it can lead to out of memory. You should also be cautious if you create dynamic atoms in your code.
But, you can use the .
to retrieve the data from the keys as map.key
unlike the usual notation like map["key"]
. That really saves on typing. But, I don’t encourage this because, as programmers we should really care about memory.
Be sure that when you try to retrieve a key with .
form which is not present in the map, it will raise a key error instead of returning the nil
unlike the map["key"]
which returns nil
if key
is not present in a map
.
Elixir >=1.4.0
has ANSI color printing option to console. You can have great fun with colors. You can also provide background colors.
The red prints in red color, green in green color, yellow in yellow color and normal in white. Have fun with colors…
For more details on color printing check Printex module which I created for fun in Elixir.
We cannot make use of the functions as guard clauses in elixir. It means, when
cannot accept custom defined functions. Consider the following lines of code…
Here we defined a module Hello
and a function hello
that takes two parameters of name
and age
. So, based on age I am trying IO.puts
accordingly. If you do so you will get an error saying….
This is because when cannot accept functions as guards. We need to convert them to macros
Lets do that…
In the above lines of code, we wrapped all our guards inside a module MyGuards
and make sure the module is top of the module Hello
so, the macros first gets compiled. Now compile and execute you will see the following output..
Starting on Elixir v1.6, you can use defguard/1.
The defguard
is also a macro. You can also create private guards with defguardp
. Hope, you got the point here.
Consider the following example.
NOTE: The defguard
and defguardp
should reside inside the module like other macros. It raises a compile time error, if some thing that don't fit in the guard clause section when
.
Suppose, you want to check the given number is either three
or five
, you can define the guard as following.
Usage
You can also use them inside your code logic as they results boolean
value.
Check the following execution screen shot.
Sometimes, we have to make sure that certain module is loaded before making a call to the function. We are supposed to ensure the module is loaded.
Similarly we are having ensure_compile
to check whether the module is compiled or not…
Elixir provides a special syntax which is usually used for module names. What is called a module name is an uppercase ASCII letter followed by any number of lowercase or uppercase ASCII letters, numbers, or underscores.
This identifier is equivalent to an atom prefixed by Elixir.
So in the defmodule Blackode
example Blackode
is equivalent to :"Elixir.Blackode"
When we use String.to_atom "Blackode"
it converts it into :Blackode
But actually we need something like “Blackode” to Blackode. To do that we need to use Module.concat
In Command line applications whatever you pass they convert it into binary. So, again you suppose to do some casting operations …
We all know that =
does the pattern match for left and right side. We cannot do [a, b, c] = [1, 2, 3, 4]
this raise a MatchError
We can use destructure/2
to do the job.
If the left side is having more entries than in right side, it assigns the nil
value for remaining entries..
We can decorate our output with inspect
and label
option. The string of label
is added at the beginning of the data we are inspecting.
If you closely observe this it again returns the inspected data. So, we can use them as intermediate results in |>
pipe operations like following……
You will see the following output
We can pass the anonymous functions in two ways. One is directly using &
like following..
This is the most weirdest approach. How ever, we can use the reference of the anonymous function by giving its name.
The above style is much better than previous . You can also use fn
to define anonymous functions.
Or use Kernel.then/2
function since 1.12.0