Give a try on

5 Things you might not have tried in Elixir | Advanced

Better try and fail than being idle.

Blackode
Blackode
Apr 15 · 6 min read
Photo by Viktor Talashuk on Unsplash

While learning to program in Elixir, I discovered some strange things. In this post, I dive into the 5 strange approaches that you may or may not know to expose its underlying mechanisms.

Talk is cheap, here is the code.

1. Compile Time Vs Run Time Struct Pattern Matching — In Different way

We all know that structs can be pattern matched with %StructName{}

Consider the following struct Student

defmodule Student do
defstruct name: "john"
end

We generally use the following approach to pattern match the above struct. But, it expects the struct to be available at the compile time itself.

%Student{} = student

The struct can also be pattern matched as

%{__struct__: Student} = student

But it won’t give any error if the struct isn’t available at the compile time.

Let’s check both approaches.

[1]. Approach: %ModuleName{ }

Here, we pattern match struct as %Student{} and module must be available by the time defining the print anonymous function.

Let’s check what if we load the print function first here

# Load firstprint = 
fn %Student{} = student ->
IO.inspect student.name
end
# Load Nextdefmodule Student do
defstruct name: "john"
end

It gives you a ** (CompileError) Student.__struct__/0 is undefined

[2]. Approach %{__struct__: StructName}

Here, we pattern match struct as %{__struct__: Student} like any regular map expecting a key as __struct__ and its value as Student.
As we all know that struct will have an extra key __struct__ with value as module name it was defined in, here the Student .

Here, we simply pattern match __struct__ key.

# Load firstprint = 
fn %{__struct__: Student} = student ->
IO.inspect student.name
end
# Load Nextdefmodule Student do
defstruct name: "john"
end

Check the difference between these two approaches in the following screenshot while executing in iex

Approach 1 will make sure of the availability of the struct at compile time unlike approach 2.

I hope you got the idea about when to use and which approach to use. But, at the production level, we mostly see the approach 1 style %Student{}. We need to ensure the existence of struct.

2. Re Bounding can Fail in Elixir in some cases

We all know that in elixir we have the freedom of rebounding a variable. That means, consider x = 5 and after some statements, we can rebound the variable x to some other value as x = 10

Did you ever try to rebound in the same instruction?

Try this

iex> [a, b, a] = [1, 2, 3]

What is the value of a here?

Up on execution, it gives you the match error ** (MatchError) no match of right hand side value: [1, 2, 3]

Let’s try this again with

iex> [a, b, a] = [1, 2, 1]

Now, a is equals to 1

You can use this logic when you expect something to be matched exactly before.

3. Converting IO lists to Binary

In Elixir, we use IO module functions for input/output handling. The building of IO data is much cheaper than the concatenation of strings. When we do concatenation through string interpolation #{}that means we are duplicating the data here. Explaining those terms is beyond the scope of this article.

Consider the following lines of code

:erlang.iolist_to_binary [1, 2, 3, 4, 5, 255]

This works fine.

Now, let’s try with number > 255

:erlang.iolist_to_binary [1, 2, 3, 4, 5, 256]

This gives you an argument error saying ** (ArgumentError) argument error
:erlang.iolist_to_binary([1, 2, 3, 4, 5, 256])

The integers in IO data are considered as bytes while integers in chardata are Unicode points.

Bytes are integers in range 0..255
Unicode are integers in the range 0..0x10FFFF i.e. 0..17825776

4. Converting The Improper lists to Binary

I hope you already knew about the improper list structure in Elixir. If not know more about improper lists.

Now, let’s convert the improper lists to binary. Before we go further, we need to understand how we define the iolist.

Check the following screenshot.

So, IO list can be empty_list [] or Binary or [iohead|iotaill] and

:erlang.iolist_to_binary ["foo" | "1"]

This works as expected since iohead and iotail for the give list is of type Binary.

[iohead|iotail]
=
["foo" | "1"]

here, iotail is "1" is Binary

From the definition, the only iohead can have numbers and tails are only allowed [], binaries and other IO Lists.

Now, let’s make iotail to number from range 0..255

:erlang.iolist_to_binary ["foo" | 1]

This still gives you an argument error as iotail is neither [] nor Binary nor iolist

5. Aliasing Erlang Module into Elixir Module

As we all know that Elixir ModuleNames are just atoms. For example, the module name Student is equivalent to an atom of style :"Elixir.Student"

iex> Student == :"Elixir.Student"
true

We can do alias the erlang module to some Elixir module name style.

alias :math, as: Math
alias :math, as: :"Elixir.MathLib"

However, you cannot alias the Erlang module to some other Erlang module name style.

alias :math, as: :math2
#This gives you the compile time error

Happy Coding !!

Join Our Telegram Channel Blackoders

Check out the GitHub repository on Killer Elixir Tips

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