Elixir Programming Language
Andrew Schutt
@schuttandrew
Who am I?
Why learn Elixir?
Why learn Elixir?
Why learn any language?
- Languages don't use a single paradigm
- Different languages solve the same problems in different ways
- New opportunities
Theme from previous languages
- All Object Oriented
- All Imperative languages
Why did I learn Elixir?
- Functional Programming
- Similarity to Ruby
- Phoenix web framework
- Built on Erlang VM
Imperative
a programming paradigm that uses statements that change a program's state.
Declarative
describing what the program must accomplish in terms of the problem domain, rather than describe how to accomplish it
Functional Programming
programming paradigm treats computation as the evaluation of functions
Immutable Values
- Variables are immutable
First Class Functions
- Functions can be...
- variables
- arguments
- return values
- anonymous
Pure Functions
- same input = same output
Recursion
- Recursion
- Recursion
- Recursion
- Recursion
- Recursion!
- Recursion
- Recursion
- Recursion
Elixir
- Erlang
- History
- Tooling (Mix, IEX, ExDoc, Pry)
- Syntax
- Types
- Data Structures
- Pattern Matching
- First Class Functions
- Guard Clauses
- Control Flow
- Pipe Operator
Erlang
- Proven
- Fault Tolerant
- Hot Swap
- OTP
History
- created 2011
- Josè Valim creator
Tools
- IEX
- h method
- ExUnit
- DocTest
- Mix
Syntax
Types
- Integer
- Float
- String
- Bitstring
- Boolean
- Atom
- Tuple
- List
- PID
BitString and String
'string?' == "string?"
false
is_list 'string?
true
String.valid?("string?")
true
Atom
:atom
:true == true
true
Tuple
{1, 2, 3, 4}
{1, 2.0, :atom, {"a", "tuple"}, "cool"}
List
[1, 2, 3, 4]
[1, 2.0, :atom, {"a", "tuple"}, ["a", ['list']]
List
list = [1, 2, 3, 4]
[ head | tail ] = list
head
1
tail
[2, 3, 4]
new_list = ["new head" | list ]
["new head", 1, 2, 3, 4]
List
list = [1, 2, 3, 4, 5, 6]
[ 1, 2, third | rest ] = list
third
3
rest
[4, 5, 6]
[ 2, 3, third | rest ] = list
MatchError!
Keyword List
keyword_list = [key: "value"]
keyword_list[:key]
"value"
Keyword List
[{:key, "value"}] == [key: "value"]
true
Enum
list = [1, 2, 3]
Enum.map(list, fn(x) -> x * 2 end)
[2, 4, 6]
Enum.map(list, &(&1 * 2))
Binding
a = 1
b = 2
a = 3
^a = 1
false
^a = 3
true
a
3
Binding
value = 100
old_val = fn -> IO.puts "value was #{value}" end
#Function
old_val.()
value was 100
value = 1234
value
1234
old_val.()
value was 100
Dot Notation
value = 100
old_val = fn -> IO.puts "value was #{value}" end
#Function
old_val.()
value was 100
value = 1234
value
1234
old_val.()
value was 100
Pattern Matching
a = 1
[_, 2, 3] = [1, 2, 3]
[_, 2, 3] = [{:value}, 2, 3]
[_first, _second, third] = [1, 2, 3]
_first
[1, 2, 3] = [2, 3, 4]
MatchError!
First Class Functions
add = fn n1, n2 -> n1 + n2 end
subtract = fn n1, n2 -> n1 - n2 end
perform_calc = fn n1, n2, func ->
func.(n1, n2)
end
perform_calc.(5, 6, add)
11
Control Flow
if true do
"it's true!"
end
if done do
"all done!"
else
"still doing something"
end
unless orange do
"not orange"
end
Control Flow
temp = 30
cond do
temp >= 212 -> "Boiling"
temp <= 32 -> "Freezing"
temp <= -459.67 -> "Absolute Zero"
end
Case Statements
calculate = fn expression ->
case expression do
{:+, num1, num2} -> num1 + num2
{:-, num1, num2} -> num1 - num2
{:*, num1, 0} -> 0 #short circuit
{:*, num1, num2} -> num1 * num2
{:/, num1, num2} -> num1 / num2
end
end
calculate.({:+, 1, 2})
3
Guard Clauses
{:/, num1, num2} when num2 != 0 -> num1 / num2
grade = "A"
good_job = fn(grade) when grade in ["A"] do
IO.puts "good job"
end
good_job.(grade)
"good job"
Pipe Operator
IO.puts "hello"
"hello"
"hello" |> IO.puts
"hello"
Enum.map([1, 2, 3], fn i -> i * 2)
[2, 4, 6]
[1, 2, 3] |> Enum.map(fn i -> * 2)
[2, 4, 6]
- find user by token
- fetch user messages
- convert response to JSON
- save messages
Pipe Operator
- find user by token
- fetch user messages
- convert response to JSON
- save messages
def import_messages
Enum.each(
parse_json_to_message_list(
fetch(find_user_by_token(token), "messages/")
), &save_message(&1)
end
Pipe Operator
- find user by token
- fetch user messages
- convert response to JSON
- save messages
def import_messages
token
|> find_user_by_token
|> fetch("messages/")
|> parse_json_to_message_list
|> Enum.each(&save_message(&1)
end
Pipe Operator
Module
defmodule CoffeeCup do
def start_drinking(oz) when oz > 0 and oz < 20 do
IO.puts "Cup is full with #{oz} oz"
drink_up(oz)
end
defp drink_up(0), do: get_more
defp drink_up(oz_left) do
IO.puts oz_left
drink_up(oz_left - 1)
end
def get_more do
IO.puts "Get more coffee!"
end
end
Phoenix
- MVC
- Similar Project Structure
- Scaffolding
- Channels
- Performance
Phoenix New
Very simple to get a new Phoenix project up and going similar to Rails
Running the above commands generates a simple Twitter clone.
mix phoenix.new example_app
mix ecto.create
mix phoenix.gen.html Comment comments body:string username:string
mix ecto.migrate
Channels
Performance
Switch Now!
DO NOT
ACTUALLY
SWITCH
In Conclusion...
Resources:
- Programming Elixir
- Dave Thomas
- Elixir in Action
- Saša Jurić
- Elixir Sips (videocasts)
- Josh Adams
- elixir-lang.org
- phoenixframework.org
- Elixir Fountain (podcast)
- Johnny Winn
- Quick References
Thank you!
@schuttandrew
Elixir Talk for Iowa Ruby Brigade
By Andrew Schutt
Elixir Talk for Iowa Ruby Brigade
a presentation for Iowa Ruby Brigade presenting on the Elixir programming language
- 928