Elixir Introduction

by "Blag" - Senior Developer Evangelist

Return to Geeky Thursday

What is Elixir?


Elixir is a functional, concurrent, general-purpose programming language that runs on the Elixir Virtual Machine (BEAM).


Elixir builds on top of Erlang and share the same abstractions for building distributed, fault-tolerant applications.


Erlang functions can be called from Elixir without run time impact, due to compilation to Erlang bytecode and vice versa.

How to install Elixir?


On Ubuntu

Add wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb

Run sudo apt-get update

Install the Erlang/OTP platform sudo apt-get install esl-erlang

Install Elixir sudo apt-get install elixir

How to install Elixir?


On Mac

For Homebrew brew update

For Homebrew brew install elixir


For MacPorts sudo port install elixir

How to install Elixir?


On Windows

Download the installer

Click next, next, …, finish


Who uses Elixir?


  • Adobe -> Combined client/cloud application for collaborative photography workflow
  • Erlang Solutions -> On-site/remote Elixir and Erlang consulting
  • Pinterest -> Visual discovery tool that you can use to find ideas for all your projects and interests
  • Pivotal -> Wrote the new RabbitMQ CLI and are pushing Elixir through their engineering blog
  • Slack -> Build a media server for p2p and group calls
  • Teachers pay teachers -> Empowering millions of educators to share their work, their insights, and their inspiration with one another. Based in NYC, Elixir powers our backend infrastructure.

Starting out...


To begin with...we're going to call Elixir from the terminal.


Variables


Variables are not variable...


Once assigned...variables cannot change...they're immutable...

Although, and unlike Erlang...we can rebind them...which basically means we separate a new memory address and then get rid of the previous one...

				
myvariable = "This is my variable".

"This is my variable"



myvariable = "This could be your variable".

"This could be your variable"



#Not the same variable...the second "myvariable" 

#is a new variable pointing to the first 

#"myvariable" address...
				

Unlike Erlang...commands do not to end with a period "."


Variables must start with an lowercase letter.


Starting with a Uppercase letter creates an "atom".


Atoms are not variables, but string representations...like Constants.


Elixir has dynamic typing...what you assign to a value, it becomes its type...

				
ThisIsAnAtom

#ThisIsAnAtom


:ThisIsAnAtomAsWell

#:ThisIsAnAtomAsWell


thisisanatom = "My Atom".

#** (MatchError) no match of right hand 

#    side value: "Hello"



integerValue = 1977

1977
				

Tuples

Sometimes, we need to group values together...


For that, we can use Tuples...


				
person = {"blag", 40}.

# {blag, 40}



{name,age} = person.

# {blag, 40}



person = put_elem(person, 1, 41)

# 41


age

# 40


age = elem(person, 1)

# 41
				

We can create nested tuples...

				
anotherPerson = {"Wolverine", 210}.

# {"Wolverine", 210}



people = {person,anotherPerson}.

# {{"Blag", 37},{"Wolverine", 210}}
				

Lists

We can use Lists to handle Tuples in a better way...

				
people = [{"Blag",37},{"Wolverine",210},{"Bart",11}]

# [{"Blag",37},{"Wolverine",210},{"Bart",11}]



[head|tail] = people

# [{"Blag",37},{"Wolverine",210},{"Bart",11}]



head

# {"Blag",37}



tail

# [{"Wolverine",210},{"Bart",11}]
				

Strings

Strings are not strings...They're either Binary or List

				
"Hello World"

# "Hello World"



[72,101,108,108,111,32,87,111,114,108,100].

# 'Hello World'



?H

# 72



[87]

# "W"
				

Our first application


For this application we need to create a file called "greetings.exs" (with all lowercase)...


				
defmodule Greetings do

  def greet(:male, name) do

    IO.puts("Good morning Mr. #{name}")

  end
  

  def greet(:female, name) do

    IO.puts("Good morning Mrs. #{name}")

  end
  

  def greet(_, name) do

    IO.puts("Good morning ??? #{name}")

  end  

end
				

Before we can call our App, we need to compile it...


Run elixirc greetings.exs


This is going to create Elixir.Greetings.beam


Run iex


And the call it like this Greetings.greet(parameters)


When we run it we're going to see...


Functions

Function are very important...In Elixir everything is a function.


There's no such things as Classes or Objects.


We can define the same function name with different number of parameters.


They will be treated as completely different functions.


Recursion is very important...we'll see that later...


Our second application

This example will call the same function with different number of parameters...


You can call it "numbers.exs" (with all lowercase)


				
defmodule Numbers do

  def num(a) do

    IO.puts("This is your number #{a}")

  end


  def num(a, b) do

    IO.puts("This is the sum of two numbers #{a + b}")

  end  

end    
				

When we run it we're going to see...


Recursion

Recursion is one of the key points in Elixir...you call a function that calls itself multiple times.


Also, we can use something called "Pattern Matching" which is used to determine which function to call...

Our third application

This example will create a Fibonacci Number Generator.


You can call it "fibonacci.exs" (with all lowercase)


				
defmodule Fibonacci do

  def fib(number) do

    fib(number, 0, 1, "")

  end
  

  def fib(1,_,_,acc) do

    IO.puts("0 1 " <> acc)

  end  
  

  def fib(number, a, b, acc) when a > 0 do

    fib(number - 1, a + b, a, acc <> 
    
        to_string(a+b) <> " ") 

  end
				
				
  def fib(number, a, b, acc) do

    fib(number - 1, a + b, b, acc <> 
    
        to_string(a+b) <> " ") 

  end

end 
				

When we run it we're going to see...


Making an LED Number App


Name your file "led_Numbers.exs"


				
defmodule LED_Numbers do

  def showLED(num) when is_number(num) do

    digits = for x <- to_charlist(num) do

               x - 48

             end
				
				
    leds = %{0 => {" _  ","| | ","|_| "},

             1 => {"  ","| ","| "},

             2 => {" _  "," _| ","|_  "},

             3 => {"_  ","_| ","_| "},

             4 => {"    ","|_| ","  | "},

             5 => {" _  ","|_  "," _| "},

             6 => {" _  ","|_  ","|_| "},

             7 => {"_   "," |  "," |  "},

             8 => {" _  ","|_| ","|_| "},

             9 => {" _  ","|_| "," _| "}}

    build_output(digits,digits,leds,0,"")	     

  end
				
				
  def build_output(_,_,_,3,acc) do

    IO.puts(acc)

  end
  

  def build_output([],digits,leds,lineNo,acc) do

    build_output(digits,digits,leds,lineNo + 1,
    
                 acc <> "\n")

  end
  

  def build_output([h|t],digits,leds,lineNo,acc) do

    build_output(t,digits,leds,lineNo,
    
                 acc <> elem(leds[h],lineNo))

  end  

end
				

When we run it we're going to see...


Random Names


This App will generate 100,000 random names using two 16 elements arrays


We will measure the runtime


Name your file "randomNames.exs"


				
defmodule RandomNames do

  def show_names() do
  

    names = ["Anne","Gigi","Blag","Juergen",

             "Marek","Ingo","Lars","Julia",

             "Danielle","Rocky","Julien",

             "Uwe","Myles","Mike","Steven",

             "Fanny"]
             

    last_names = ["Hardy","Read","Tejada",

                  "Schmerder","Kowalkiewicz",

                  "Sauerzapf","Karg","Satsuta",

                  "Keene","Ongkowidjojo",

                  "Vayssiere","Kylau","Fenlon",

                  "Flynn","Taylor","Tan"]
				
				
    generateNames(names, last_names)              

  end
  

  def generateNames(names, last_names) do

    _ = for _ <- (1..100000) do

          Enum.at(names,Enum.random(0..15)) <> " " <> 
          
          Enum.at(last_names,Enum.random(0..15))

        end

    IO.puts("Done")   

  end
			
				
  def run_names() do

    {time, _} = :timer.tc(fn -> 
    
                   RandomNames.show_names 
                 
                 end, [])

    IO.puts(time/1_000_000)

  end

end
			

When we run it we're going to see...

So, what about Erlang?

Decimal to Romans


This App will create a Roman Numeral based on a decimal number


This will include some nice commands...


Name your file "decToRomans.exs"


				
defmodule DecToRomans do

  def showRomans(number) when is_number(number) do

    romanNums = [{1000,"M"},{900,"CM"},{500,"D"},

                 {400,"CD"},{100,"C"},{90,"XC"},

                 {50,"L"},{40,"XL"},{10,"X"},

                 {9,"IX"},{5,"V"},{4,"IV"},{1,"I"}]

    showRomans(number,romanNums,0,"") 

  end

  

  def showRomans(0,_,_,acc) do

    IO.puts(acc)

  end
			
				
  def showRomans(number, romanNums, counter, acc) do

    key = elem(Enum.at(romanNums, counter), 0)

    value = elem(Enum.at(romanNums, counter), 1)

    case number >= key do

      true -> showRomans(number - key, romanNums, 
      
                         counter, acc <> value)

      false -> showRomans(number, romanNums, 
      
                          counter + 1, acc)

    end

  end

end
			

When we run it we're going to see...


Concurrency


Create processes in Elixir is both easy and inexpensive.

We can create a dozen, hundrer or even thousand of processes...and they act independentely.

Name your file "concurrent.exs"


				
defmodule Concurrent do

  def proc(n)do

    :timer.sleep(3000)

    IO.puts("Process #{n}")

  end

  

  def spawn_proc(n) do

    spawn(fn -> Concurrent.proc(n) end)

  end

  

  def run_non_concurrent() do

    Enum.each(1..5, &Concurrent.proc(&1))

    Concurrent.proc("Another process")

  end
			
				
  def run_concurrent() do

    IO.inspect(Enum.each(1..5, 
    
               &Concurrent.spawn_proc(&1)))

    Concurrent.proc("Another process")

  end  

end



#{time, _} = :timer.tc(fn -> 

#              Concurrent.run_non_concurrent end, [])

#IO.puts(time/1_000_000)



#{time, _} = :timer.tc(fn ->

#              Concurrent.run_concurrent end, [])

#IO.puts(time/1_000_000)
			

Let's uncomment the non-concurrent call and see how it fares...

Let's do the same for the concurrent version...

That's all for now...


I hope you had some fun...


I hope you liked Elixir


I hope you will give Functional Programming a second look -;)


Contact Information


Blag --> blag@blagarts.com

@Blag on Twitter

Go back home...