Elixir v1.4 brings new features, enhancements and bug fixes into Elixir. The most notable changes are the addition of the Registry
module and the Task.async_stream/3
and Task.async_stream/5
which aid developers in writing concurrent software. Those two features and a couple other improvements are described in detail below followed by the complete list of changes.
The registry is a local, decentralized and scalable key-value process storage:
- Local because keys and values are only accessible to the current node (opposite to distributed)
- Decentralized because there is no single entity responsible for managing the registry
- Scalable because performance scales linearly with the addition of more cores upon partitioning
A registry is chosen upon start to have unique or duplicate keys. Every key-value pair is associated to the process registering the key. Keys are automatically removed once the owner process terminates.
iex> Registry.start_link(:unique, MyRegistry)
iex> {:ok, _} = Registry.register(MyRegistry, "hello", 1)
iex> Registry.lookup(MyRegistry, "hello")
[{self(), 1}]
With the registry, developers can provide dynamic process names, module-function dispatch or even a local pubsub system. See the Registry
documentation for more information.
Elixir v1.4 introduces the ability to syntax color inspected data structures:
iex> IO.puts inspect([hello: 1, world: "!"], syntax_colors: [atom: :cyan])
[hello: 1, world: "!"]
Coloring is done with ANSI colors as specified in the IO.ANSI
module.
IEx automatically relies on this feature to provide syntax coloring for evaluated shell results. This behaviour can be configured via the :syntax_colors
coloring option:
IEx.configure [colors: [syntax_colors: [atom: :cyan, string: :green]]]
To disable coloring altogether, pass an empty list to :syntax_colors
.
Elixir v1.3 introduced new calendar types. This release continues evolving the Calendar APIs by adding functions for comparing, adding and calculating the difference between types, retrieve the day_of_week/1
, check if the current date is a leap_year?/1
and more.
When there is a need to traverse a collection of items concurrently, Elixir developers often resort to tasks:
collection
|> Enum.map(&Task.async(SomeMod, :function, [&1]))
|> Enum.map(&Task.await/1)
While the snippet above works fine in many occasions, for large collections it will spawn and run concurrently as many tasks as there are items in the collection.
Task.async_stream/3
and Task.async_stream/5
allows developers to process collections concurrently while controlling the maximum amount of concurrent tasks:
collection
|> Task.async_stream(SomeMod, :function, [], max_concurrency: System.schedulers_online)
The Task.async_stream
functions are also lazy, allowing developers to partially consume the stream until a condition is reached. Furthermore, Task.Supervisor.async_stream/4
and Task.Supervisor.async_stream/6
can be used to ensure the concurrent tasks are spawned under a given supervisor.
Mix v1.4 now automatically infers the list of applications that are required on runtime from your dependencies list.
In previous Mix versions, most of your dependencies had to be added both to your dependencies list and applications list. Here is how a mix.exs
would look like:
def application do
[applications: [:logger, :plug, :postgrex]]
end
def deps do
[{:plug, "~> 1.2"},
{:postgrex, "~> 1.0"}]
end
This was error prone as many developers would not list their dependencies in their applications list.
Mix v1.4 now automatically infers your applications list as long as you leave the :applications
key empty. The mix.exs
above can be rewritten to:
def application do
[extra_applications: [:logger]]
end
def deps do
[{:plug, "~> 1.2"},
{:postgrex, "~> 1.0"}]
end
With the above, Mix will automatically build your application list based on your dependencies. Applications that are part of Erlang or Elixir that are required at runtime, such as :logger
, must be added to the :extra_applications
list. All extra applications will be included in the application list.
Finally, if there is a dependency you don't want to include in the application runtime list, you can do so by specifying the runtime: false
option:
{:distillery, "> 0.0.0", runtime: false}
We hope this feature provides a more streamlined workflow for developers who are building releases for their Elixir projects.
Mix v1.4 can now install escripts and archives from both Git and Hex, providing you with even more options for distributing Elixir code.
This makes it possible to distribute CLI applications written in Elixir by publishing a package which builds an escript to Hex. ex_doc
has been updated to serve as an example of how to use this new functionality.
Simply running:
mix escript.install hex ex_doc
will fetch ex_doc
and its dependencies, build them, and then install ex_doc
to ~/.mix/escripts
(by default). After adding ~/.mix/escripts
to your PATH
, running ex_doc
is as simple as:
ex_doc
You can now also install archives from Hex in this way. Since they are fetched and built on the user's machine, they do not have the same limitations as pre-built archives. However, keep in mind archives run alongside every Mix project, which may lead to conflicts. For this reason, escripts is the preferred format.
It is also possible to install escripts and archives by providing a Git/GitHub repo. See mix help escript.install
and mix help archive.install
for more details.
This version includes changes that make Elixir fully compatible with Erlang/OTP 20.
- [Logger] Handle changes to crash reports in OTP 20
- [DateTime] Fix
DateTime.from_iso8601/2
when offset has no colon - [Registry] Do not leak EXIT messages on
Registry.dispatch/3
This version includes changes that make Elixir fully compatible with Erlang/OTP 20-rc.1.
- [Map] Fix regression on struct update syntax
This version includes changes that make Elixir fully compatible with Erlang/OTP 20-rc.1.
- [Kernel] Improve compilation time for modules with many clauses
- [Map] Warn when attempting to override
__struct__
key - [Regex] Add
recompile/1
andrecompile!/1
to ease transition to OTP 20 for archives and stored regexes
- [Logger.Translator] Handle OTP 20 GenServer log messages
- [mix compile] Recompile projects if OTP version changes
- [Kernel] Fix code generation when non-binary bitstrings are in AST
- [Record] Properly escape fields passed to
defrecord
- [Version] Reject leading zeros according to the SemVer spec
- [ExUnit.Diff] Do not fail when comparing maps with nil or boolean keys
- [IEx.Helpers] Do not log exits on
IEx.Helpers.c/2
failures
- [mix archive.install] Detect proper path on URLs with query strings
- [mix loadpaths] Do not assume all paths in loadpaths exist
- [EEx] Support middle expressions on trim mode
- [Calendar] Correct typo on Calendar types
- [Kernel] Ensure redefined functions point to the proper source
- [OptionParser] Add
:allow_nonexistent_atoms
to support unsafe behaviour prior to v1.4 - [Stream] Allow consuming multiple items from suspended enumerable in
Stream.transform/3
- [String] Incorporate new grapheme rules in Unicode 9
- [IEx.Autocomplete] Do not crash on aliases which are not known at compile time
- [Mix.Umbrella] Ensure umbrella projects can depend on other umbrella projects
- [Mix.Archive] Ensure previous archives with
.ez
extension are deleted
- [Kernel] Remove warning when making private functions overridable
- [Path] Ensure
Path.join/1
returns strings for lists of one element - [Regex] Ensure
Regex.escape/1
also escapes-
- [IEx] Disable ANSI detection for powershell to avoid false positives
- [Mix.Make] Run
make clean
forerlang.mk
- [Mix.Rebar] Support all of rebar3 dependency package declaration
- [Mix.Rebar] Only pass overrides from parent to child in Rebar dep
- [Calendar] Add
Date.compare/2
,Time.compare/2
,NaiveDateTime.compare/2
andDateTime.compare/2
- [Calendar] Support
NaiveDateTime.add/3
andNaiveDateTime.diff/3
for adding seconds (up to microseconds) as well as the difference between two NaiveDateTimes in seconds (up to microseconds) - [Calendar] Add
Date.leap_year?/1
andDate.day_of_week/1
- [Calendar] Ensure
Date
,Time
andNaiveDateTime
APIs work with any struct that provides the same set of fields as their respective struct. For example, aNaiveDateTime
can be given toDate
since it contains a superset of the fields in theDate
struct - [Calendar] Add
Time.utc_now/0
andNaiveDateTime.utc_now/0
- [Enum] Add
Enum.map_every/2
that invokes the given function with every nth item - [Enum] Add
min/2
,max/2
,min_max/2
,min_by/3
,max_by/3
, andmin_max_by/3
that allow a function specifying the default value when the enumerable is empty - [Enum] Introduce
Enum.zip/1
to zip multiple entries at once - [Float] Introduce
Float.ratio/1
that returns a tuple with the numerator and denominator as integers to retrieve the given float - [GenServer] Log warn on default
handle_info/2
implementation - [Inspect] Support syntax coloring via the
:syntax_color
option - [Integer]
Integer.digits/2
now accepts negative integers - [Integer] Add
Integer.mod/2
andInteger.floor_div/2
- [IO] Add
:label
option toIO.inspect/2
to help distinguish multipleIO.inspect/2
calls. - [Kernel] Recognize merge conflict markers in source and provide a readable error message
- [Kernel] Warn on unused module attributes
- [Kernel] Improve compiler message on unexpected end of line
- [Kernel] Raise
BadBooleanError
when a non-boolean is given on the left-hand side ofand
/or
- [List] Add
List.pop_at/3
- [List] Add
List.myers_difference/2
- [OptionParser] Expand multi-letter aliases in
OptionParser
- [Process] Add
Process.send_after/4
- [Process] Improve error messages on
Process.register/2
errors - [Registry] Add a local, decentralized and scalable key-value process storage
- [Stream] Add
Stream.map_every/2
that invokes the given function with every nth item - [Stream] Introduce
Stream.zip/1
to lazily zip multiple entries at once - [String] Update to Unicode 9.0.0
- [Task] Add
Task.async_stream/3
andTask.async_stream/5
as well as the supervised versionsTask.Supervisor.async_stream/4
andTask.Supervisor.async_stream/6
- [URI] Allow 0 as URI scheme default port
- [ExUnit.Diff] Use red or green background for whitespace-only diffs
- [ExUnit.Doctest] Allow inspected structures with multiples lines and unicode characters in the doctest result
- [ExUnit.Formatter] Replace lhs/rhs with left/right in the formatter for clarity
- [IEx.Autocomplete] Stop appending a trailing dot when autocompleting modules in IEx
- [IEx.Autocomplete] Support autocompletion for structs
- [IEx.Autocomplete] Improve IEx autocomplete to support navigating map atom keys
- [IEx.Helpers]
c/1
now compiles in memory by default to avoid common issue where.beam
files remain at projects root directory - [IEx.Helpers] Add info about protocols in
i/1
- [IEx.Server] Support interrupting IEx evaluation through the Ctrl+G prompt
- [mix archive] Compress archive files built by
mix archive
as they are now unzipped during installation - [mix archive] Install from SCM
- [mix compile] Automatically infer the list of applications for Mix projects
- [mix cmd] Add the ability to specify one or more apps in
mix cmd
- [mix deps] Warn if there are non-applications in the
apps
directory for umbrella projects - [mix deps] Add warning for invalid paths on
mix deps.clean
- [mix deps] Add
Mix.Project.apps_paths
that returns the paths to children applications in umbrella projects - [mix deps] Add
MIX_REBAR
environment variable for overriding local rebar - [mix escript] Install from SCM
- [mix new] Check directory existence in
mix new
and ask how to proceed if one exists - [mix new] Applications built with the
--sup
flag now have an individual module to work as application callback - [mix test] Add
--formatter
option tomix test
- [mix xref] Provide "did you mean?" suggestions for
mix xref
- [Access] Do not accept nils in
Access.key/1
andAccess.key/2
in favor of explicit default values (or Access.key!/1 if you expect the key to always be available) - [Float] Avoid multiple roundings in
Float.ceil/2
,Float.floor/2
andFloat.round/2
- [Kernel] Don't crash in
macro_exported?/3
when dealing with Erlang modules - [Kernel] Ensure locals calls are rewritten when calling a local function or macro from inside a module
- [Kernel] Annotate the context for variables as zero-arity funs in quotes
- [Kernel.SpecialForms] Ensure comprehensions with guards and filters keep proper ordering,
- [Kernel.SpecialForms] Produce meaningful warning when with's else clauses have no effect
- [Macro] Wrap fn calls in parens in
Macro.to_string/2
- [Macro] Do not print aliases as keys inside keyword lists in
Macro.to_string/2
- [OptionParser] Support options in
OptionParser.to_argv/2
to ensure:count
switches are correctly encoded - [Stream] Ensure
Stream.take/2
does not consume next element on:suspend
- [String] Fix infinite recursion in
String.replace_leading/3
andString.replace_trailing/3
when given an empty string - [Task] Fix
Task.shutdown/1,2
infinite block when task has no monitor - [Task] Ensure task cannot link after parents unlinks
- [ExUnit] Fix a race condition in
assert_receive
where we would assert a message was not received but show it in the list of messages when the message is delivered right after the timeout value
- [IEx.Helpers] Purge consolidated protocols before and after
recompile/0
- [Mix.Dep] Use
gmake
on FreeBSD instead ofmake
when compiling make dependencies - [Mix.Project] Only copy files from source when they're newer than destination (for Windows machines)
- [Mix.Task] Ensure non-recursive tasks inside umbrella are reenabled
- [Enum]
Enum.partition/2
has been deprecated in favor ofEnum.split_with/2
- [System] Deprecate plural time units in favor of singular ones to align with future Erlang releases
- [ExUnit] Using GenEvent to implement ExUnit formatters is deprecated. Please use the new
GenServer
based formatters instead
- [Access]
Access.key/1
is deprecated due to erratic behaviour for missing keys, please useAccess.key/2
instead with proper default values - [Behaviour] The
Behaviour
module is deprecated. Callbacks may now be defined directly via the@callback
attribute - [Enum] Deprecate
Enum.uniq/2
in favor ofEnum.uniq_by/2
- [Float]
Float.to_char_list/2
andFloat.to_string/2
are deprecated (use the:erlang.float_to_list/2
and:erlang.float_to_binary/2
functions if such conversions are desired) * [HashDict] TheHashDict
module is deprecated, in favour of theMap
* [HashSet] TheHashDict
module is deprecated, in favour of theMapSet
* [Kernel] Deprecate support for making private functions overridable. Overridable functions must always be public as they must be contracts - [Kernel] Anonymous functions with no expression after
->
, in favor of using an expression or returningnil
- [Kernel] Warn if variable is used as a function call
- [OptionParser] Deprecate aliases with multiple letters, such as
-abc
- [Set] Deprecation of the
Set
module in favor ofMapSet
- [Stream] Deprecate
Stream.uniq/2
in favor ofStream.uniq_by/2
- [IEx.Helpers]
import_file/2
is deprecated in favor ofimport_file_if_available/1
- [Mix.Utils]
underscore/1
andcamelize/1
are deprecated in favor ofMacro.underscore/1
andMacro.camelize/1
The CHANGELOG for v1.3 releases can be found in the v1.3 branch.