Date post: | 07-Feb-2017 |
Category: |
Technology |
Upload: | cory-gwin |
View: | 100 times |
Download: | 1 times |
ELIXIRGETTING STARTED WITH HIGHLY SCALABLE, SUPER SEXY SYSTEMS
INTRO
WHAT IS ELIXIR
▸ Erlang / Erlang Compatible
▸ Functional
▸ Ruby like Syntax
▸ Scalable
▸ Interactive Shell (REPL) and Compiled
▸ Able to run hundreds of thousands of processes on a single machine.
INTRO
WHAT IS ERLANG?
▸ Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability.
▸ First appeared in 1986
▸ Distributed, Fault-Tolerant, High availability, Hot swappable.
▸ Erlang was designed with the aim of improving the development of telephony applications by Ericsson
▸ As Tim Bray, director of Web Technologies at Sun Microsystems, expressed in his keynote at OSCON in July 2008: If somebody came to me and wanted to pay me a lot of money to build a large scale message handling system that really had to be up all the time, could never afford to go down for years at a time, I would unhesitatingly choose Erlang to build it in.
INSTALL
LETS INSTALL
▸ Mac - Homebrew: brew install elixir
▸ Mac - MacPorts: sudo port install elixir
▸ Linux or Windows: http://elixir-lang.org/install.html
PACKAGE AND ENV MANAGEMENT
MIX
▸ Builds project skeleton - mix new project-name
▸ Compile projects - mix compile
▸ Manages dependencies - mix.esx file, install with mix deps.get
▸ def deps do
▸ [{:plug, "~> 1.0"}]
▸ end
▸ Test Runner - mix test
▸ mix help
SETUP
START A NEW PROJECT
▸ Start a new project
▸ cd to directory
▸ mix new learn
▸ cd learn
▸ mix test
▸ Lets look
GETTING STARTED
RUNNING
▸ iex (iex.bat on windows) - Interactive REPL
▸ elixir: runs a script (elixir simple.exs)
▸ elixirc: Compile to beam file and run.
▸ iex filename.exs
▸ inside iex > c “filename.ex”
▸ iex -S mix # include the current project into iex
GETTING STARTED
FILE TYPES
▸ .exs - For interpreted code.
▸ .ex - For compiled code.
▸ .beam - Compiled byte code via Erlang abstract format
DATA TYPES
BASIC TYPES
▸ Integers: 1
▸ Float: 0.1
▸ Boolean: true
▸ Symbol/atom: :name
▸ String: “hello”
▸ list (Linked list): [1, 2, 3]
▸ tuple: {1, 2, 3}
MATH
BASIC ARITHMETIC
▸ 1 + 2
▸ 5 * 5
▸ 10 / 2 (returns float)
▸ div(10, 2) rem(10, 2)
▸ round(4.2)
▸ trunc(4.6)
DATA TYPES
STRINGS
▸ x = “world”
▸ String interpolation “Hello #{x}”
▸ line break \n
▸ String.length("hello")
▸ String.upcase(“hello")
▸ ‘hello’ creates a character list, which is not what you expect.
DATA TYPES
LINKED LISTS
▸ [1, 2, true, 3]
▸ [1 | [2 | [3 |[]]]] # The pipe operator is the glue
▸ length [1, 2, 3]
▸ [1, 2, 3] ++ [4, 5, 6]
▸ [a | b] = [1, 2, 3, 4]
DATA TYPES
TUPLE
▸ tuple = { :ok, “elixir”, 2 }
▸ tuple_size tuple
▸ elem(tuple, 1)
▸ put_elem tuple, 1, “new”
▸ tuple
DATA TYPES
TUPLE OR LINKED LIST?
▸ Linked lists shouldn’t be used to retrieve items at an index
▸ Getting the length of a linked list is linear time
▸ Updating a list is fast as long as you are prepending
▸ Tuples are stored contiguously in memory, allowing easier access to single item or size
▸ Tuples are for small data sets
▸ Tuples are often used for returning multiple items from a function.
DATA TYPE
IMMUTABILITY
▸ Variables in elixir are just pointers.
▸ You can point a variable at a different block of memory, but you cannot change a block of memory that has been instantiated.
▸ Also you can pin a variable for pattern matching so it does not rebind - ^a = 1
▸ Functions cannot change the variable you pass into them.
DATA TYPE
IMMUTABLE EXERCISE
▸ Try this:
▸ tuple = var = {1, 2, 3}
▸ put_elem tuple, 1, “new”
▸ tuple
▸ var
▸ tuple = put_elem tuple, 1, “new”
▸ tuple
▸ var
ARRAYS?
WHERE IS THE ARRAY?
▸ Elixir has chosen to leave out some of the data types offered by Erlang. The array is one of the common data types developers may miss.
▸ Immutable programming is one reason it has been left out.
▸ A little array song and dance about memory, sorting and mutability.
▸ This is a highly debated topic in the community.
PATTERN MATCHING
=, I DON’T THINK IT MEANS WHAT YOU THINK
▸ x = 1
▸ 1 = x
▸ 2 = x
▸ {a, b, c} = {1, 2, 3}
▸ a
▸ {a, b, c} = {:hello, “world” } # check the number of args match
▸ {:ok, count} = {:error, 11} # ok is an atom, so it doesn't match
▸ {:ok, count} = {:ok, 9}
▸ count
DATA TYPES
KEYWORD LISTS
▸ [a: 10, b: 5] = [{:a, 10}, {:b, 5}]
▸ kwl = [{:name, “Cory”}, {:from, “Wisconsin”}, {:from, “California”}, {:from, “Pennsylvania”}]
▸ List.keyfind(kwl, “Cory”, 1) # find cory position 1
▸ List.keydelete(kwl, “Cory”, 1)
▸ kwl = List.keyreplace(kwl, :name, 0, {:first_name, “Cory”})
DATA TYPE
MAPS
▸ map = %{ name: “Cory”, from: “Wisconsin”, city: “Madison”}
▸ Map.keys map
▸ Map.values map
▸ map[:name]
▸ map.name
▸ Map.put map, :current, “Pennsylvania”
▸ %{ name: name_pointer} = map
DATA TYPES
MAPS OR KEYWORD LISTS
▸ Pattern match against the contents, for example matching a dictionary that has a key in it? - Map
▸ More than 1 entry with the same key? - Keyword module
▸ Guaranteed order? Keyword module
▸ Anything else - use a map
▸ (taken from Programming Elixir 1.2 book)
CONDITIONALS
CONDITIONAL LOGIC
▸ ==, !=, ===, !==, >, >=, <, <=
▸ and, or, not
▸ is_atom/1, is_float/1
▸ if true do: something
▸ unless true do: something
▸ if true do
▸ something
▸ else
▸ something else
▸ end
CONDITIONALS
THE WAR ON IF
▸ There is no “if else”
▸ Prefer guard functions, case or cond
CONDITIONALS
CASE
▸ You can use pattern matching in your cases, cases are usually returns from functions
▸ result = case {1, 2, 3} do
▸ {4, 5, 6} -> “This will not match”
▸ {1, 2, 3} -> “This will match and evaluate”
▸ end
CONDITIONALS
CONDITION
▸ The condition is useful when you need to check multiple possible conditions. Returns the first one that evaluates as true
▸ result = cond do
▸ 2 + 2 == 5 -> “This will fail”
▸ 2 + 2 == 4 -> “Suscess”
▸ true -> “A default case”
▸ end
FUNCTIONS
ANONYMOUS FUNCTION
▸ multiply = fn a, b -> a * b end
▸ multiply.(2, 3)
▸ double = fn a -> multiply.(a, 2) end
▸ functions define their own scope
▸ x = 1
▸ (fn -> x = 3 end).()
▸ x
▸ 1
MODULES
MODULES
▸ Group of functions
▸ String.length(“Chimera”)
▸ defmodule Chimera do
▸ def register(name) do
▸ do something cool
▸ end
▸ end
EXERCISE
BUILD A SIMPLE FUNCTION
▸ Test file - math_test.exs
▸ defmodule LearnTest do
▸ use ExUnit.Case
▸ test “Sum two numbers” do
▸ assert Learn.sum(1, 1) == 2
▸ end
▸ end
▸ Get this test to pass
FUNCTIONS
GUARD FUNCTIONS
▸ It is possible to have multiple functions with the same name that are executed based on some sort of pattern match or expression.
▸ pattern(%{ name: “” }), do: “Error name needed”
▸ pattern(%{name: name}) when name == “Cory”, do: “Hello Creator”
▸ pattern(%{ name: name}), do: “Hello #{name}”
FUNCTIONS
FUNCTIONS
▸ Guard Functions, great for recursion
▸ def MyMath do
▸ def sum([], total), do: total
▸ def sum([ head | tail ], total), do: sum(tail, head+total)
▸ end
FUNCTION
THE PIPE OPERATOR
▸ The |> operator passes data
▸ [from: "Wi", from: "CA"] |> List.keyfind(:from, 0)
▸ is the same as List.keyfind([from: "Wi", from: “CA”], :from, 0)
▸ Object Oriented “self” tangent here
SCHEMAS
HOW TO MODEL YOUR DATE
▸ Structs are a way to model complex common data structures.
▸ Structs are maps.
▸ Module can combine data and associated functions.
▸ defmodule User do
▸ defstruct name: nil, age: nil, address: nil
▸ def name(user), do: Map.fetch(user, :name)
▸ end
▸ user = %User{name: “Cory”, age: 37, address: “Pittsburgh” }
▸ User.name(user)
DEBUGGING TIPS
IO.INSPECT
▸ IO.inspect will print complex data types to STDOUT
▸ IO.inspect user
▸ Can be pipped into and returns what ever was piped into it.
▸ “Hellos World” |> String.replace(“s”, “”) |> IO.inspect |> String.split() |> IO.inspect
DEBUGGING
PRY
▸ Jump into a running session with an iex.pry
▸ require IEx;
▸ defmodule Example do
▸ def double_sum(x, y) do
▸ IEx.pry
▸ hard_work(x, y)
▸ end
▸ defp hard_work(x, y) do
▸ 2 * (x + y)
▸ end
▸ end
▸ iex -S mix
DEBUGGING
ERLANG DEBUGGER
▸ Erlang offers a built in breakpoint debugger.
▸ iex -S mix
▸ :debugger.start() # Start the process
▸ :int.ni(Learn) # Register the module
▸ :int.break(Learn, 3) # Set the breakpoint, line 3 of learn module
▸ Learn.sum(1, 2) # Run the code you want to debug
EXERCISES
REFACTOR
▸ Refactor this code, so you do not need to pass the total as an argument
▸ http://bit.ly/29WzscO
EXERCISES
FIZZ BUZZ
▸ Print the number 1-100 replacing multiples of 3 with the word “Fizz” and multiples of 5 with the word “Buzz”. If the word is a multiple of 5 and 3 then print FizzBuzz.
▸ ex:
▸ 1 2 Fizz 4 Buzz Fizz… 13 14 FizzBuzz
EXERCISES
BUILD A MAP TOOL
▸ Build a function that can accept a list and another function and excute the function on each item in the list returning a new list.
▸ MyMap.map([1, 2, 3], fn(item) -> item + 1 end)
▸ [2, 3, 4]
WHAT TO LEARN NEXT
NEXT TOPICS
▸ Iterating, mapping and recursion. Everything is a list.
▸ OTP - Abstraction layer for handling concurrency, supervising, fault tolerance, etc…
▸ Phoenix - Web Framework, Rails like
▸ Ecto - domain specific language for writing queries and interacting with databases
▸ Nerves - Embedded software for micro controllers.
▸ Meta-programming