Notes on learning Elixir - Part 1
![Notes on learning Elixir - Part 1](/content/images/size/w1200/2023/12/elixir.jpg)
Disclaimer: I have been programming for a while, but I am a complete Elixir n00b. These are my unfiltered notes while learning the Elixir language. Official Getting Started documentation is where I started the learning process. I tried to write as many tiny code snippets as I could with already learned syntax. If you think I have misunderstood a concept, then please let me know and I can add corrected information next to my original misunderstanding.
Background and why learn Elixir?
I think we all can agree that learning a new programming language is always beneficial. By learning the language I don't mean that you should memorize the whole syntax or even use it in your day job, it is more than enough that you keep mind open and reflect the ideas back to whatever you're doing on a daily basis.
Picking a programming language is worth of its own blog post. There are plenty of choices varying from Haskell to Clojure, what made me learn Elixir:
- I wanted something different than I already knew (I have done written production code with C#, Java, Delphi and JavaScript)
- functional programming concepts such as (built-in) immutability
- positive comments on Erlang VM (aka BEAM, Elixir is based on this) and its rock-solid performance and stability
- Dave Thomas has been really into ElixirSee note 1
- it is not too academic programming language, and it seems to have powerful libraries/frameworks: Phoenix (Web framework) and Ecto (database handling using Elixir, "ORMish")
Note 1: Dave Thomas helped introduce Ruby language to the western world and got famous by writing The Pragmatic Programmer together with Andy Hunt. I think he knows what he is talking about, unlike me. grin
Notes
Installation
- went to through Windows installation that installed Erlang and Elixir
- iex / iex.bat => Interactive Elixir aka REPL
- Elixir files end with .exs
- installed a plugin for Sublime to the syntax highlighting
- code is executed with command elixir (no surprises there!)
Data types
- integers, floats, booleans, atoms, strings, lists and tuples. All good and familiar.. wait, Atoms?
- division always returns a float, even when dividing doesn't leave the remainder (10 / 5 = 2)
- I wonder how currencies are handled as I didn't see Decimal data type
- no semicolons, parenthesis are not required => Win
- if you want a Float, you just put dot and digit to the end. 1 (Integer), 1.0 (Float). Simple
- it is interesting that the math operations are not in a namespace or a module such as Math.round
- you can check types with built-in functions
is_boolean
,is_float
etc. - "Atoms are constants where their name is their own value. Some other languages call these symbols". Interesting.
- atoms have a colon in front of them
:ok
- string interpolation support, nice! Some languages just recently got that feature, for example, C#
- list items can be any type
- tuples combined with atoms seems to be common practice
Basic operators
- I wonder why lists are concatenated like this:
[1,2,3] ++ [4,5,6]
, but strings using"foo" <> "bar"
- got an answer from Slack channel: strings are handled as a byte buffer and therefore
<>
operator - operators like
and
,or
are strict,1 and true
is not valid as both sides have to have a boolean value. Very strict when coming from JavaScript background! But fear not,||
and&&
can have other values than booleans. - all values except
false
andnil
will evaluate totrue
- Oh no, nightmares from JavaScript world,
===
exists! Gladly it's meaning is different than preventing automatic type conversion. It is used only when comparing integers and floats.
iex> 1 == 1.0
true
iex> 1 === 1.0
false
Pattern matching
- I vaguely remember pattern matching principles from Haskell
- "the = operator in Elixir is actually a match operator and how to use it to pattern match inside data structures. " Trying to forget assignment and thinking about matching..
- pattern matching can look similar to ES2015 destructuring assignment {a, b, c} = {:hello, "world", 42}, but that seems to be a just small glimpse of the whole matching story
- this is a much more powerful feature than I expected. Lots of nice examples of more advanced matching
iex> [head | tail] = [1, 2, 3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
And
iex> {:ok, result} = {:ok, 13}
{:ok, 13}
iex> result
13
iex> {:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}
- The 'Pin' operator made my head hurt. This StackOverflow answer was helpful.
- it is super-interesting how the language has immutability and still you can do this:
list = sort(list)
list = filter(list)
list = do_something_with(list)
list = another_thing_with(list)
Instead of writing "temporary" variables:
SortedList = sort(List),
FilteredList = filter(SortedList),
List3 = do_something_with(FilteredList),
List4 = another_thing_with(List3)
case, cond and if
- found this pattern matching section from "Learn you some Erlang"
- pattern matching combined with guards looks powerful feature.
iex> case {1, 2, 3} do
...> {1, x, 3} when x > 0 ->
...> "Will match"
...> _ ->
...> "Would match, if guard condition were not satisfied"
...> end
"Will match"
- it is interesting that error is not raised when the guard does an illegal operation
iex> case 1 do
...> x when hd(x) -> "Won't match"
...> x -> "Got: #{x}"
...> end
"Got 1"
- hd(x) is taking a head from an array and the argument x is invalid. It will go to "unmatching" guard.
cond
is equivalent toelse if
in imperative languages
Binaries, strings and char lists
- the chapter contains excellent overview about UTF-8 and Unicode
- good reminders about utf-8 and how text length correlation with byte size is not always linear
- because different characters require a different amount of bytes built-in function
byte_size
andString.length
will return a different answer - putting a question mark before the character will display code point value
iex> ?ł
322
- I was a bit too tired for sections "Binaries (and bitstrings)" and "Char lists".
- Elixir seems to handle all sorts of weird Unicode edge-cases
Conclusion of Part 1
I would like to continue learning, but my brain gave a warning about possible BufferOverflowException, so I'd better continue learning on Part 2. Even if this was just a fraction of things to learn, I already started to get into the mode where things don't look weird and threatening. When you come from the object-oriented background, it might feel weird to write hd my_list
instead of my_list.hd
, but we should be able to change the way we think and write our software.
Be sure to comment, it is highly appreciated! Until next time.