Woo, quite a long title, but I think that effectively explains what this is going to be about. There are already lots of good posts on Elixir from proper Erlang programmers. This isn’t meant to be another one of them. It’s just a collection of things I’ve noticed.
It is pretty much the same
Superficially there is no real difference (or benefit to be gained) between Erlang and Elixir code. Here’s some Erlang code:
pad_to(Length, Binary_string) when length(Binary_string) < Length ->
Padded_binary_string = "0"++Binary_string,
pad_to(Length, Padded_binary_string);
pad_to(Length, Binary_string) when length(Binary_string) == Length ->
Binary_string.
And the equivalent in Elixir:
def pad_to(length, binary_string) when length(binary_string) < length do
padded_binary_string = '0'++binary_string
pad_to(length, padded_binary_string)
end
def pad_to(length, binary_string) when length(binary_string) == length do
binary_string
end
Apart from the wrapping of the code in def
and end
it looks pretty much the same.
You have to still use Erlang
Quite a bit. I was surprised how quick I came across the need to do this, but not all Erlang things have Elixir equivalents so you have to use Erlang code; However, at least this is seamless and painless.
Original Erlang:
Binary_string = hd(io_lib:format("~.2B", [Binary_number])),
Elixir port:
binary_string = hd(:io_lib.format("~.2B", [binary_number]))
defp is really neat
In Erlang you export only the functions you want:
-module(polyline).
-export([six_bit_chunks/1]).
six_bit_chunks(Encoded_polyline) ->
six_bit_chunks_(Encoded_polyline, []).
six_bit_chunks_([Head | Rest], Chunks_list) ->
Six_bit_chunk = six_bit_chunk(Head),
%Add to Reversed_chunks
six_bit_chunks_(Rest, [Six_bit_chunk]++Chunks_list);
six_bit_chunks_([], Chunks_list) ->
lists:reverse(Chunks_list).
In Elixir everything that uses def
is exported automatically. If you don’t want something exported you use defp
. This is really neat.
def six_bit_chunks(encoded_polyline) do
six_bit_chunks_(encoded_polyline, [])
end
defp six_bit_chunks_([head | rest], chunks_list) do
six_bit_chunk = six_bit_chunk(head)
#Add to Reversed_chunks
six_bit_chunks_(rest, [six_bit_chunk]++chunks_list)
end
defp six_bit_chunks_([], chunks_list) do
Enum.reverse(chunks_list)
end
Indices are different
I don’t know why, but indices are different. I don’t think there is a clever reason. It just is.
In Erlang lists:sublist("words", 2, 3)
returns “ord”. And in Elixir Enum.slice('words', 2, 3)
returns ‘rds’; That is something else to be aware off the differences in single and double quotes; single quotes are charlists as per Erlang, whereas double quotes are for Elixir strings (something different).
Flipping order of args… and pipes.
In Elixir some functions have the order of the arguments flipped from how they are in Erlang. This threw me to start with and I thought it was to make Ruby programmers happy, but actually it’s because of pipes.
In Erlang:
Eight_bit_chunks = lists:map(
fun(Group_of_chunks) ->
eight_bit_chunks(Group_of_chunks)
end,
Five_bit_chunks).
In Elixir the list, etc is always first:
eight_bit_chunks = Enum.map(
five_bit_chunks,
fn(group_of_chunks) ->
eight_bit_chunks(group_of_chunks)
end)
This means you can then do things like this:
five_bit_chunks
|> Enum.map(
fn(group_of_chunks) ->
eight_bit_chunks(group_of_chunks)
end)
I.e. pull out and pipe five_bit_chunks
into the Enum.map
. Which doesn’t look that impressive on its own but it means you can chain things together. Pipes are neat. My only quibble is that it is a step towards Haskell’s esoteric symbols (I liked Erlang over Haskell just because it was a little easier to understand).
Phoenix
I am mid-way through porting my Erlang command line application to Elixir. My plan is to then use Phoenix to turn this into a web application so other people (ha!) can use it. I also have plans to improve it. Slow, long term plans. I mention this only to say that you can write Ruby without going near Rails and the same is true of Elixir and Phoenix; and both are something you should do.