Represent numbers, names, ranges and regular expressions.
Can be written as:
- decimal (1234).
- hexadecimal (0xcafe).
- octal (0o765).
- binary (0b1010).
May contain underscores, often used to separate groupes of three digits. So one million could be written as 1_000_000
.
No fixed limit on their size.
- Must be at least one digit before and after decimal point.
- OPtional trailing exponent may be given.
1.0 0.2456 0.314158e1 314159.e-5
- Constants that represent something's name. Starts with a
:
which is followed by an atom word or Elixir operation. - Atom word is sequence of letters, digits, underscores and
@
and may end with!
or?
. - Can also create atoms with arbitrary characters by enclosing the characters in double quotes.
- Atoms:
:fred :is_binary? :var@2 :<> :=== :"func/3" :"long john silver"
An atom's name is its value. Two atoms with the same name will always compare as being equal.
Rages represented as start..end where start and end are integers.
- Written as
~r{regexp}
or~r{regexp}opts.
Resources in the underlying Erland VM.
- PID is a reference to a local or remote process.
- PID of the current process by calling
self
. - New PID created when you spawn a new process.
- Port is a reference to a resource (usually external to the app) that yuo are reading or writing to.
make_ref
function creates a globally unique reference. No other reference is equal to it.
Can hold values of any type (including other collections)
- Ordered collection of values
- Written between braces, comma separated
{1, 2} { :ok, 42, "next"} { :error, :enoent }
Typically have 2 to 4 elements. If you need more elements look at maps or structs.
- Can use tuples in pattern matching:
{status, count, action} = { :ok, 42, "next"}
# {:ok, 42, "next"}
status
# :ok
count
# 42
action
# "next"
- Common for functions to return a tuple where the first element is the atom
:ok
if there are no errors.
{status, file} = File.open("mix.exs")
# {:ok, #PID<0.39.0>}
Common to write matches that assume success.
The second ope fails and returns a tuple where the first element was :error
. This causes the match to fail.
{:ok, file} = File.open("mix.exs")
# {:ok, #PID<0.39.0>}
{:ok, file} = File.open("non-existent-file")
** (MatchError) no match of right hand side value: {:error, :enoent}
- Not the same as an array. (tuples are closer to an array)
- List is a linked data structure.
- Is either empty or has a head and a tail.
- head contains a value and the tail is a list (like lisp)
- Easy to traverse linearly - expensive to access in random order.
[1, 2, 3] ++ [4, 5, 6] # concatenation
# [1, 2, 3, 4, 5, 6]
[1, 2, 3, 4] -- [2, 4] # difference
# [1, 3]
1 in [1, 2, 3, 4] # membership
# true
"wombat in [1, 2, 3, 4]
# false
Shortcut to write simple lists of key/value pairs:
[name: "Dave", city: "Dallas", likes: "Programming]
Elixir converts to list of two-value tuples:
[ {:name, "Dave"}, {:city, "Dallas"}, {:likes, "Programming}]
Can leave off square brakets if keyword list is last argument in a function call.
DB.save record, [ {:use_transaction, true}, {:logging, "HIGH"}]
can be written as:
DB.save record, use_transaction: true, logging: "HIGH"
Can also leave off the brackets if a keyword list is the last item in any context where a list is expected:
[1, fred: 1, dave: 2]
# [1, {:fred, 1}, {:dave, 2}]
{1, fred: 1, dave: 2}
# {1, [fred: 1, dave: 2]}
Collection of key/value pairs
%{ key => value, key => value }
In this example, the keys are strings.
states = %{ "AL" =< "Alabama", "WI" => "Wisconsin" }
# %{"AL" => "Alabama", "WI" => "Wisconsin"}
In this example, the keys are tuples.
responses = %{ {:error, :enoent } => :fatal, {:error, :busy} => :retry}
# {{:error, :busy} => :retry, {:error, :enoent} => :fatal}
In this example, the keys are ataoms.
colors = %{:red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff}
# %{blue: 255, green: 65280, red: 16711680}
Usually all keys are the same type but is not required.
%{"one" => 1, :two => 2, {1,1,1} => 3}
# %{:two => 2, {1, 1, 1} => 3, "one" => 1}
Can use expressions for keys:
name = "Foobar"
# "Foobar"
%{String.downcase(name} => name}
# %{"foobar" => "Foobar"}
Why does Elixir have maps and keyword lists?
-
Maps allow only one entry for a key.
-
Keyword lists allow key to be repeated.
-
Maps are efficient and can be used in pattern matching.
-
Generally use keyword lists for things like command-line paramaters and passing options
-
Use maps when you want an assoc array.
- Extract values using the key.
states = %{ "AL" =< "Alabama", "WI" => "Wisconsin" }
# %{"AL" => "Alabama", "WI" => "Wisconsin"}
states["AL"]
# "Alabama"
states["TX"]
# nil
responses = %{ {:error, :enoent } => :fatal, {:error, :busy} => :retry}
# {{:error, :busy} => :retry, {:error, :enoent} => :fatal}
response_types[{:error, :busy}]
# :retry
If keys are atoms you can use a dot notation. If no matching key with dot notation you get a KeyError
.
colors = %{:red => 0xff0000, :green => 0x00ff00, :blue => 0x0000ff}
# %{blue: 255, green: 65280, red: 16711680}
colors[:red]
# 16711680
colors.green
65280
- Useful for accessing data as a sequence of bits and bytes.
- Example: reading headers in JPEG and MP3 files.
- Binary literals enclosed between
<<
and>>
.
Syntax packs successive integers into bytes:
bin = << 1, 2 >>
# <<1, 2>>
byte_size bin
# 2
Use modifiers to controll the type and size of each individual fied. Single byte that contains three fielsd of widths 2, 4 and 2 bits.
bin = <<3 :: size(2), 5 :: size(4), 1 :: size(2)>>
# <<213>>
:io.format("~-8.2b~n", :binary.bin_to_list(bin))
# 1010101
# :ok
byte_size bin
# 1
- Holds a year, month day and a reference to the ruling calendar.
d1 = Date.new(2016, 12, 25)
# {:ok, ~D[2016-12-25])
{:ok, d1} = Date.new(2016, 12, 25)
# {:ok, ~D[2016-12-25]}
d2 = ~D[2016-12-25]
# ~D[2016-12-25]
d1 == d2
# true
d1
# ~D[2016-12-25]
inspect d1, structs: false
# "%{__struct__: Date, calendar: Calendar.ISO, day: 25, month: 12, year: 2016}"
- Contains an hour, minute, second and fractions of a second.
- Fraction stored as a tuple.
t1 = Time.new(12, 34, 56)
# {:ok, ~T[12:34:56]}
t2 = ~T[12:34:56.78]
# ~T[12:34:56.78]
t1 == t2
# false
inspect t2, structs: false
# "{:ok, %{__struct__: Time, hour: 12, microsecond: (780000, 2}, minute: 34, second: 56}}"
-
Elixir identifiers consist of upper and lowercase ASCII characters, digits and underscores.
-
May end with a
?
or!
. -
Module, record, protocol and behaviour names start with an upper case and are BumpyCase.
-
All other identifiers start with lowercase or underscore and use underscores between words.
-
If first char is
_
, Elixir doesn't report a warning if the variable is unused in a pattern match or func parameter list. -
Source files are written in UTF-8 but identifiers may only use ASCII.
-
Source files use two-char indentation for nesting, uses spaces.
-
Comments start with
#
-
Style Guide: https://github.com/christopheradams/elixir_style_guide
true
,false
andnil
.nil
treated as false in Boolean contexts. (these are aliases for atoms of the same name. Sotrue
is the same as:true
.
Most of the time any other value other than false
or nil
is treated as true. (aka truthy).