Rise your Elixir Knowledge with these

10 Killer Elixir Tips #10

Being smart can bring you more confidence

Blackode
Blackode
Feb 6, 2020 · 7 min read
Image for post
Image for post

Hey Guys!

Welcome back to another set of Elixir Tips. It’s been a great pleasure in writing and sharing with you. Let’s dive in.

1. Elixir’s Ebin Directory

iex> elixir_ebin_path = :code.lib_dir(:elixir, :ebin)

What this for ?

We can find all the protocols available by using elixir_ebin_path .

iex> elixir_ebin_path = :code.lib_dir(:elixir, :ebin)
iex> Protocol.extract_protocols([elixir_ebin_path])
Image for post
Image for post
Image for post
Image for post

2. Finding Protocol implementations

Let’s check our Enumerable protocol is implemented for bitstring or not.

iex> Enumerable.impl_for(<<>>)
nil

The output for the expression is nil which indicates the Enumerable protocol is not implemented for BitString type if it has implemented, it would give the ModuleName.

Check below 👇

iex> Enumerable.impl_for(%{})
Enumerable.Map
iex> Enumerable.impl_for(1..2)
Enumerable.Range
Image for post
Image for post

You can pass any valid structure to know the protocol implementations.

Listing All implementations of a Protocol

We can easily find a particular protocol implementations using the __protocol__

iex> Enumerable.__protocol__(:impls){:consolidated,[Map, HashSet, Date.Range, Function, File.Stream, GenEvent.Stream, HashDict,List, Range, Stream, MapSet, IO.Stream]}

In the same way, you can get more info using the following functions

def __protocol__(:module)
def __protocol__(:functions)
def __protocol__(:consolidated?)
def __protocol__(:impls)
Image for post
Image for post
Image for post
Image for post

3. Compile Time Search Patterns over Strings or Binaries

The Big string operations might be time taking ones. For an example splitting a big string.

We can build compile time search patterns using :binary.compile_pattern.

This pattern later be used in run time for splitting a string or any relevant operations over string or binary.

In one sentence, it is ready by the time it is compiled.

iex> pattern = :binary.compile_pattern("@")
{:bm, #Reference<0.1776527838.1813905411.150152>}
iex> [user, host] = String.split("john@blackode.in", pattern)
["john", "blackode.in"]
Image for post
Image for post

You can also give list of binaries for :binary.compile_pattern where each one is alternative for searching patterns.

iex> pattern = :binary.compile_pattern(["@", "#"])
{:bm, #Reference<0.1776527838.1813905411.150152>}
iex> [user, host, blog] = String.split("john@blackode#medium", pattern)
["john", "blackode", ,"medium"]
Image for post
Image for post

Read more about compile_pattern

Image for post
Image for post

4. Compiling Files to the specific Path

We can compile Elixir files to the specific path, and we can run those files from their compiled directory as it contains respective beam_files.

Assume that I have three .ex files hello.ex, shop.ex, & rates.ex in my present code directory ~/mycode/elixir .

Now, I run iex from my ~/mycode/elixir directory and I try to compile files to some other directory named as ~/mycode/elixir/beamfiles.

#~/mycode/elixiriex> files = ~w(hello.ex shop.ex rates.ex)
["hello.ex", "shop.ex", "rates.ex"]
iex> Kernel.ParallelCompiler.compile_to_path files, "beamfiles"
{:ok, [Hello, Rates, Shop], []}

Now, I change my directory to ~/mycode/elxir/beamfiles and try to run iex and execute functions from compiled modules [Hello, Rates, Shop].

Image for post
Image for post

Check them live here

Image for post
Image for post

5. Finding Package Retirements

mix hex.audit

I hope you haven’t run this in any of your projects before. If you did, then a round of applause for you.

What it does ?

It looks for all the dependencies inside your dependency tree and checks any of these has retired.

Who needs it?

Package Retirement is very important for package owners or package maintainers if they do care about their users to warn them about package security issues, it’s working condition on that version number, it's compiling status, major bug issues, etc… like and so.

If no retired packages found, then it replies with No retired packages found.

Similarly, you can also run mix hex.outdated It does what it sounds alike.

Image for post
Image for post
Image for post
Image for post

6. Finding a whether function is a Built-In or Not

This relates to Erlang

iex> :erlang.is_builtin(:erlang, :>, 2)
true

You have to provide a Module, Function, and Arity.

Image for post
Image for post

7. Number Comparison in Guard Clause

Always combine comparisons with is_number().

Why ?

defmodule Bank do
def credit(amount) when amount > 0 do
#code end
end

The above function use the guard amount > 0what if we send nil , it still evaluates to true.

iex> nil > 0
true
Image for post
Image for post

At production grade coding, one has to be cautious. We can’t risk on number especially on floats. The math on floats is harder.

So, go for

defmodule Bank do
def credit(amount) when is_number (amount) and amount > 0 do

#code

end
end
Image for post
Image for post

8. Empty map pattern matching function

As we all know that %{} matches any kind of map. So, we cannot simply pattern match it like def hello(%{}) as it matches any map.

If you want to match an empty map %{}in a function, you have to use a guard clause.

defmodule Hello do
def hello(map) when map == %{} do
IO.puts "I am hungry! My stomatch is empty"
end
def hello(map) do
IO.puts "I am done! My stomach is full"
end
end
Image for post
Image for post

You can also take the help of Kernel.map_size/1 as it is allowed in guard clause.

def hello(map) when map_size(map) == 0 do
Image for post
Image for post

9. Converting String to an Atom

This may look easy but suppose you don’t know whether the value you are getting is atom or string but you need to extract that key from a map which has keys as atoms where you have to convert the given value to atom if it is a binary.

As we are having doubt on the received value whether it is atom or string, we force convert that to an atom using String.to_existing_atom/1. It works for strings but if we try to convert atom to atom using String.to_existing_atom/1 then we will get an exception.

So, we use same function with a different style with string interpolation.

cart = %{ price: 2345, tax: 100}key1 = "price"
key2 = :price

Now, we have to extract the price using above keys.

def get_from_cart(cart, key) do
Map.get(cart, key)
end

The above function works only when key is atom. Let’s check that

Image for post
Image for post

Sol 1: Using String Interpolation

def get_from_cart(cart, key) do
key = String.to_existing_atom("#{key}")
Map.get(cart, key)
end

Use this only when you assure the atom exist. Otherwise, it throws an ArgumentError

Image for post
Image for post

Sol: 2 Using Guard clause when

def get_from_cart(cart, key) when is_binary(key) do
key = String.to_existing_atom(key)
Map.get(cart, key)
end
def get_from_cart(cart, key) do
Map.get(cart, key)
end

In Sol:1 we are converting every time, while in Sol:2 we are using guard to convert to atom or not.

Image for post
Image for post

10. Sorting Dates Improvement(Elixir v 1.10)

No more hassle to sort dates now.

Before Elixir v 1.10, we have to pass another function for proper
sorting of dates like in the following way…

iex> Enum.sort([~D[2019–12–31], ~D[2020–01–01]], &(Date.compare(&1, &2) != :lt))
[~D[2019–12–31], ~D[2020–01–01]]

Now in elixir v 1.10, you can do it as follows

iex> Enum.sort([~D[2019–12–31], ~D[2020–01–01]], Date)
[~D[2019–12–31], ~D[2020–01–01]]
iex> Enum.sort([~D[2019–12–31], ~D[2020–01–01]], {:desc, Date})
[~D[2020–01–01], ~D[2019–12–31]]

The above examples are directly copied from original documentation.

Read More about Elixir V 1.10

This article Originally Posted at Blackode Journal. Read with better syntax highlighting…

Image for post
Image for post

Happy Coding !!

Join Our Telegram Channel

Check out the GitHub repository on Killer Elixir Tips

Image for post
Image for post

Glad if you can contribute with a ★

blackode

Coding, thoughts, and ideas.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store