with
improvementsgit clone https://github.com/elixir-lang/elixir.git
cd elixir
make
./bin/iex
kiex install master
source $HOME/.kiex/elixirs/elixir-master.env
iex
From 1.2, conditional variable declaration has been deprecated.
if condition do
n = 1
else
n = 2
end
IO.puts(n)
should be written as
n = if condition do
1
else
2
end
IO.puts(n)
From 1.3 this code will also give a warning
def imperative_duplicate(str, n, opts \\ []) do
if opts[:double] do
n = n * 2
end
String.duplicate(str, n)
end
# warning: the variable "n" is unsafe as it has been set in a conditional clause
we can refactor
def functional_duplicate(str, n, opts \\ []) do
n = double_if_true(n, opts[:double])
String.duplicate(str, n)
end
defp double_if_true(n, true), do: n * 2
defp double_if_true(n, false), do: n
Compare
x = 1
with :ok <- :ok do
x = 2
end
IO.puts(x) # 1
and
x = 1
case :ok do
:ok -> x = 2
end
IO.puts(x) # 2
case
, cond
, receive
scope leakstry
, with
, for
scope do not
Scope will be consistent, no leaking
x = 1
case :ok do
:ok -> x = 2
end
IO.puts(x) # 1
Same goes for receive
, cond
, and
constructs derived, such as if
with
improvementsThe new special form with
has been introduced in 1.2
case HTTPoison.get(url) do
{:ok, %HTTPoison{body: body}} ->
case Poison.decode(body) do
{:ok, data} ->
case process_data(data) do
{:ok, _processed} = result -> result
{:error, _err} = error -> error
end
{:error, _err} = error -> error
end
{:error, _err} = error -> error
end
becomes
with {:ok, %HTTPoison.Response{body: body}} <- HTTPoison.get(url),
{:ok, data} <- Poison.decode(body),
{:ok, _processed} = result <- process_data(data) do
result
end
with
improvementsImprovements in 1.3
else
clauseelse
clauseWe want to rewrite
case create_organization(params) do
{:ok, organization} ->
case create_address(organization, params) do
{:ok, address} ->
%{organization | address: address}
{:error, changeset} -> {:error, changeset |> error_string}
end
{:error, changeset} -> {:error, changeset |> error_string}
end
else
clauseWithout with
else
clause
with {:ok, organization} <- create_organization(params),
{:ok, address} <- create_address(organization, params) do
{:ok, %{organization | address: address}}
end
|> case do
{:ok, organization} -> {:ok, organization}
{:error, changeset} -> {:error, changeset |> error_string}
end
else
clauseWith with
else
clause
with {:ok, organization} <- create_organization(params),
{:ok, address} <- create_address(organization, params) do
{:ok, %{organization | address: address}}
else
{:error, changeset} -> {:error, changeset |> error_string}
end
with
We can rewrite
case HTTPoison.get(url) do
{:ok, %Response{status_code: code, body: body}} when code in 200..299 ->
case Poison.decode(body) do
{:ok, data} -> data
_ -> :error
end
_ -> :error
end
into
with {:ok, %Response{status_code: code, body: body}}
when code in 200..299 <- HTTPoison.get(url),
{:ok, data} <- Poison.decode(body) do
data
else
_ -> :error
end
Before Elixir 1.3, two main libraries for time/date
Both are great, but not (easily) interoperable
Elixir 1.3 introduces the following types
Calendar
Date
Time
NaiveDateTime
(without timezone)DateTime
(with timezone)and will provide a ISO8601 compatible implementation
escript
installation tasksmix escript.build
produces a single easy to run binary
In Elixir 1.3, tasks to manage escript
s have been added
mix escript
mix escript.install URL
mix escript.uninstall NAME
One liner in README
mix escript.install https://example.com/my-escript
Before Elixir 1.3
From Elixir 1.3
Before 1.3 it was a little complicated to run make
With Elixir 1.3, simply add :make
to compilers
defmodule MyApp.Mixfile do
def project do
[app: my_app,
compilers: [:make] ++ Mix.compilers]
end
end
defdelegate
Before 1.3 we could write this
defdelegate [reverse(list), map(list, callback)], to: :lists, append_first: true
This is now deprecated:
warning: passing a list to Kernel.defdelegate/2 is deprecated,
please define each delegate separately
warning: Kernel.defdelegate/2 :append_first option is deprecated
defdelegate
Before 1.3 we had to write
defdelegate start_session, to: Hound.Helpers.Session
defdelegate start_session(opts), to: Hound.Helpers.Session
From 1.3, we can write
defdelegate start_session(opts \\ []), to: Hound.Helpers.Session
Process.sleep
Before 1.3, we could achieve this with :timer.sleep
Probably added mainly for documentation:
we usually do not need it
Process.sleep
alternativesTask.async fn ->
do_something()
end
Process.sleep(30_000)
parent = self()
Task.async fn ->
do_something()
send parent, :work_done
end
receive do
:work_done -> :ok
after
30_000 -> :timeout
end
Process.sleep
alternativesTask.start fn ->
do_something()
end
# Wait until task terminates
Process.sleep(30_000)
# Check if process is alive
{:ok, pid} = Task.start fn ->
do_something()
end
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, _, _, _} -> :task_is_down
after
30_000 -> :timeout
end
optionalcallback
and optionalmacrocallback
defoverridable
app.tree
and deps.tree
mix tasks$ mix deps.tree
foobar
├── gettext ~> 0.9 (Hex package)
├── cowboy ~> 1.0 (Hex package)
│ ├── cowlib ~> 1.0.0 (Hex package)
│ └── ranch ~> 1.0 (Hex package)
├── phoenix_html ~> 2.4 (Hex package)
│ └── plug ~> 0.13 or ~> 1.0 (Hex package)
│ └── cowboy ~> 1.0 (Hex package)
├── phoenix ~> 1.1.4 (Hex package)
│ ├── poison ~> 1.5 or ~> 2.0 (Hex package)
│ ├── plug ~> 1.0 (Hex package)
│ │ └── cowboy ~> 1.0 (Hex package)
│ └── cowboy ~> 1.0 (Hex package)
├── phoenix_live_reload ~> 1.0 (Hex package)
│ ├── phoenix ~> 0.16 or ~> 1.0 (Hex package)
│ └── fs ~> 0.9.1 (Hex package)
├── postgrex >= 0.0.0 (Hex package)
│ ├── decimal ~> 1.0 (Hex package)
│ ├── db_connection ~> 0.2 (Hex package)
│ │ ├── poolboy ~> 1.5 (Hex package)
│ │ └── connection ~> 1.0.2 (Hex package)
│ └── connection ~> 1.0 (Hex package)
└── phoenix_ecto ~> 2.0 (Hex package)
├── poison ~> 1.3 (Hex package)
├── phoenix_html ~> 2.2 (Hex package)
└── ecto ~> 1.1.2 (Hex package)
├── postgrex ~> 0.11.0 (Hex package)
├── poolboy ~> 1.4 (Hex package)
├── poison ~> 1.0 (Hex package)
└── decimal ~> 1.0 (Hex package)
app.tree
and deps.tree
mix tasks$ mix app.tree
foobar
├── elixir
├── phoenix
│ ├── elixir
│ ├── plug
│ │ ├── elixir
│ │ ├── crypto
│ │ └── logger
│ │ └── elixir
│ ├── poison
│ │ └── elixir
│ ├── logger
│ │ └── elixir
│ └── eex
│ └── elixir
├── phoenix_html
│ ├── elixir
│ ├── logger
│ │ └── elixir
│ └── plug
│ ├── elixir
│ ├── crypto
│ └── logger
│ └── elixir
├── cowboy
│ ├── ranch
│ ├── cowlib
│ │ └── crypto
│ └── crypto
├── logger
│ └── elixir
├── gettext
│ ├── elixir
│ └── logger
│ └── elixir
├── phoenix_ecto
│ ├── elixir
│ ├── logger
│ │ └── elixir
│ └── ecto
│ ├── elixir
│ ├── logger
│ │ └── elixir
│ ├── decimal
│ │ └── elixir
│ └── poolboy
└── postgrex
├── elixir
├── logger
│ └── elixir
├── db_connection
│ ├── elixir
│ ├── logger
│ │ └── elixir
│ └── connection
│ └── elixir
└── decimal
└── elixir
Soon enough?