Changelog for Elixir v1.5
December 19, 2017 · View on GitHub
Elixir v1.5 brings new features, enhancements and bug fixes to Elixir. It is the first release to leverage features added as part of Erlang/OTP 20. It is also the last release that supports Erlang/OTP 18.
UTF-8 atoms, function names and variables
Elixir v1.5 supports non-quoted atoms and variables to be in UTF-8 when using Erlang/OTP 20+. For example:
test "こんにちは世界" do
assert :こんにちは世界
end
Or:
saudação = "Bom dia!"
Elixir follows the recommendations in Unicode Annex #31 to make the language more accessible to other languages and communities. Identifiers must start with a letter or underscore, optionally followed by letters, digits, and underscores. Here letter means any UTF-8 letter-character (optionally with a combining mark) and digit means a UTF-8 decimal-digit-character. If you're using ASCII, this does what you'd expect.
Examples of valid variables are:
name josé _age まつもと _42 адрес
Examples of invalid variables include:
name• a±2 42
Symbols, such as mathematical notations and emoji, are not allowed identifiers.
For a complete reference on Elixir syntax, see the Syntax Reference. For technical details on Unicode support, see Unicode Syntax.
IEx improvements
IEx got many improvements. The autocompletion system is now capable of autocompleting variables and user imports. New helpers have also been added:
exports/1lists all exports (functions and macros) in a given moduleopen/1opens up the source of a module or function directly in your editor. For example,open MyApp.Moduleruntime_info/0prints general information about the running system, such as number of cores, runtime version, allocation of memory in the VM and more
IEx also features a breakpoint system for code debugging. The following functions have been added to aid debugging:
break!/2- sets up a breakpoint for a givenMod.fun/aritybreak!/4- sets up a breakpoint for the given module, function, aritybreaks/0- prints all breakpoints and their idscontinue/0- continues until the next breakpoint in the same processopen/0- opens editor on the current breakpointremove_breaks/0- removes all breakpoints in all modulesremove_breaks/1- removes all breakpoints in a given modulereset_break/1- sets the number of stops on the given id to zeroreset_break/3- sets the number of stops on the given module, function, arity to zerrespawn/0- starts a new shell (breakpoints will ask for permission once more)whereami/1- shows the current location
Exception.blame
Exception.blame/3 is a new function in Elixir that is capable of attaching debug information to certain exceptions. Currently this is used to augment FunctionClauseErrors with a summary of all clauses and which parts of clause match and which ones didn't. For example:
iex> Access.fetch(:foo, :bar)
** (FunctionClauseError) no function clause matching in Access.fetch/2
The following arguments were given to Access.fetch/2:
# 1
:foo
# 2
:bar
Attempted function clauses (showing 5 out of 5):
def fetch(-%struct{} = container-, key)
def fetch(map, key) when -is_map(map)-
def fetch(list, key) when -is_list(list)- and is_atom(key)
def fetch(list, key) when -is_list(list)-
def fetch(-nil-, _key)
(elixir) lib/access.ex:261: Access.fetch/2
In the example above, an argument that did not match or guard that did not evaluate to true are shown between -. If the terminal supports ANSI coloring, they are wrapped in red instead of the - character.
Since blaming an exception can be expensive, Exception.blame/3 must be used exclusively in debugging situations. It is not advised to apply it to production components such as a Logger. This feature has been integrated into the compiler, the command line, ExUnit and IEx.
This feature also requires Erlang/OTP 20+.
Streamlined child specs
Elixir v1.5 streamlines how supervisors are defined and used in Elixir. Elixir now allows child specifications, which specify how a child process is supervised, to be defined in modules. In previous versions, a project using Phoenix would write:
import Supervisor.Spec
children = [
supervisor(MyApp.Repo, []),
supervisor(MyApp.Endpoint, [])
]
Supervisor.start_link(children, strategy: :one_for_one)
In Elixir v1.5, one might do:
children = [
MyApp.Repo,
MyApp.Endpoint
]
Supervisor.start_link(children, strategy: :one_for_one)
The above works by calling the child_spec/1 function on the given modules.
This new approach allows MyApp.Repo and MyApp.Endpoint to control how they run under a supervisor. This reduces the chances of mistakes being made, such as starting an Ecto repository as a worker or forgetting to declare that tasks are temporary in a supervision tree.
If it is necessary to configure any of the children, such can be done by passing a tuple instead of an atom:
children = [
{MyApp.Repo, url: "ecto://localhost:4567/my_dev"},
MyApp.Endpoint
]
The modules Agent, Registry, Task, and Task.Supervisor have been updated to include a child_spec/1 function, allowing them to be used directly in a supervision tree similar to the examples above. use Agent, use GenServer, use Supervisor, and use Task have also been updated to automatically define an overridable child_spec/1 function.
Finally, child specifications are now provided as maps (data-structures) instead of the previous Supervisor.Spec.worker/3 and Supervisor.Spec.supervisor/3 APIs. This behaviour also aligns with how supervisors are configured in Erlang/OTP 18+. See the updated Supervisor docs for more information, as well as the new Supervisor.init/2 and Supervisor.child_spec/2 functions.
@impl
This release also allows developers to mark which functions in a given module are an implementation of a callback. For example, when using the Plug project, one needs to implement both init/1 and call/2 when writing a Plug:
defmodule MyApp do
@behaviour Plug
def init(_opts) do
opts
end
def call(conn, _opts) do
Plug.Conn.send_resp(conn, 200, "hello world")
end
end
The problem with the approach above is that, once more and more functions are added to the MyApp module, it becomes increasingly harder to know the purposes of the init/1 and call/2 functions. For example, for a developer unfamiliar with Plug, are those functions part of the MyApp API or are they implementations of a given callback?
Elixir v1.5 introduces the @impl attribute, which allows us to mark that certain functions are implementation of callbacks:
defmodule MyApp do
@behaviour Plug
@impl true
def init(_opts) do
opts
end
@impl true
def call(conn, _opts) do
Plug.Conn.send_resp(conn, 200, "hello world")
end
end
You may even use @impl Plug if you want to explicitly document which behaviour defines the callback you are implementing.
Overall, using @impl has the following advantages:
-
Readability of the code is increased, as it is now clear which functions are part of your API and which ones are callback implementations. To reinforce this idea,
@impl trueautomatically marks the function as@doc false, disabling documentation unless@docis explicitly set -
If you define
@implbefore a function that is not a callback, Elixir will error. This is useful in case of typos or in case the behaviour definition changes (such as a new major version of a library you depend on is released) -
If you use
@implin one implementation, Elixir will force you to declare@implfor all other implementations in the same module, keeping your modules consistent
Calendar improvements
This release brings further improvements to Calendar types. It adds arithmetic and others functions to Time, Date, NaiveDateTime and Datetime as well as conversion between different calendars.
v1.5.3 (2017-12-19)
1. Bug fixes
Elixir
- [Calendar] Consider microseconds in maximum possible Calendar.ISO datetime
- [Enum] Fix
chunk_every/4whenstep > count - [Kernel] Warn duplicate definitions in macros
- [Kernel] Remove dialyzer warnings from else in with clauses
- [Kernel] Do not warning on upcoming
@deprecatedand@sinceattributes for v1.6 - [MapSet] Return valid MapSet when union-ing a legacy MapSet
ExUnit
- [ExUnit] Fix compiler warnings in
assert_receive/3
v1.5.2 (2017-09-29)
1. Enhacements
Elixir
- [Kernel] Optimize function definition with multiple clauses by not traversing the internal clauses table
- [Kernel] Warn if unary operators are followed by new lines
- [Registry] Use the name of the Registry as its
:idin thechild_spec/1function
2. Bug fixes
Elixir
- [DateTime] Fix negative microsecond result when passing negative Unix epochs to
from_unix/2 - [Kernel] Improve error message for oversized atoms
- [Kernel] Ensure
@implattribute also propagates to clauses from default arguments - [Kernel] Emit proper error for unknown vars inside binary pattern in match
IEx
- [IEx] Do not crash IEx unexpectedly on
System.stop/0 - [IEx.Helpers] Ensure exiting a breakpoint set inside a breakpoint does not terminate the shell unexpectedly
Mix
- [mix local.hex] Ensure
--if-missingflag works as advertised - [mix test] Do not trigger additional error reports when there is a failure when loading test files
- [Mix.SCM.Git] Ensure errors when invoking
gitpropagate correctly
v1.5.1 (2017-08-01)
1. Enhancements
EEx
- [EEx.Engine] Add
handle_beginandhandle_endto EEx
Elixir
- [Kernel] Do not use references on function/macro definitions - this provides large improvements in compilation times in some rare corner cases
- [Supervisor] Support mixing old and new typespecs in
Supervisor.init/2andSupevisor.start_link/2
Mix
- [mix profile] Allow profile tasks to run without a project
2. Bug fixes
EEx
- [EEx.Engine] Do not re-use the value of the
init/1callback throughout the compilation stack
Elixir
- [Kernel] Ensure dialyzer does not emit warnings in some uses of
with - [Kernel] Fix dialyzer warnings when
defmacropis used in modules - [Kernel] Ensure Elixir modules can be dialyzed without starting the Elixir application
- [Kernel] Do not serialize references in quoted expressions
- [Kernel] Make sure structs expansion use the latest definition available when struct modules are recompiled
- [Task] Support
:infinitytimeout on Task streams - [Typespec] Ensure typespecs allow
tupleto be used as variable names
v1.5.0 (2017-07-25)
1. Enhancements
Elixir
- [Access] Optimize
Access.get/2 - [Base] Optimise Base encode/decode
- [Calendar] Implement Inspect for DateTime with Calendar.ISO
- [Calendar] Add "ISO days" format for conversions between Calendars and
Date.convert/2,Time.convert/2,NaiveDateTime.convert/2andDateTime.convert/2(as well as bang variants) - [Calendar] Add
:calendarfield toTimestruct - [Calendar] Add
Time.diff/3,Date.add/2,Date.diff/2,DateTime.diff/3 - [Calendar] Add
Date.range/2 - [Calendar] Add
Date.new/4,DateTime.utc_now/1,NaiveDateTime.new/8andTime.new/5that allow specifing calendar - [Enum] Add
Enum.chunk_by/4andStream.chunk_by/4 - [Enum] Add
Enum.chunk_every/2andEnum.chunk_every/4with a more explicit API thanEnum.chunk/2andEnum.chunk/4 - [Exception] Add
Exception.blame/3that adds metadata to exceptions - [File] Add
File.read_link/1andFile.read_link!/1 - [File] Introduce
:trim_bomoption forFile.stream!/2 - [Inspect] Add
:printable_limitto control the limit of printable structures - [Integer] Add
Integer.gcd/2 - [Kernel] Add
left not in rightto check that the left side is not in the enumerable on the right - [Kernel] Use the new
debug_infochunk in OTP 20. This provides a mechanism for tools to retrieve the Elixir AST from beam files - [Kernel]
defoverridable/1accepts a module name as argument and marks all callbacks as overridable - [Kernel] Allow non-quoted Unicode atoms and variables according to Unicode Annex #31 (see Unicode Syntax document)
- [Kernel] Warn when a
:__struct__key is used when building/updating structs - [Kernel] Cache the AST on definitions. This speeds up the compilation time from 10% to 15% measured across different projects
- [Kernel] Improve compiler error message on invalid patterns and guards
- [Keyword] Add
replace/3andreplace!/3for replacing an existing key - [List]
List.starts_with?/2 - [Macro] Introduce
Macro.generate_arguments/2 - [Map] Optimize
Map.merge/3by choosing merging direction - [Map] Add
replace/3andreplace!/3for replacing an existing key - [Map] Raise
BadMapErrorinMap.equal?/2when either of the two arguments is not a map - [MapSet] Reduce
MapSetsize when serialized to approximately half - [Process] Add
Process.cancel_timer/2 - [Protocol] Show available implementations on
Protocol.UndefinedErrorif the protocol has been consolidated - [Registry] Support ETS guard conditions in
Registry.match/3 - [Registry] Support
parallel: trueinRegistry.dispatch/3 - [Registry] Introduce
Registry.unregister_match/4 - [Stream] Add
Stream.chunk_every/2andStream.chunk_every/4with a more explicit API thanStream.chunk/2andStream.chunk/4 - [String] Optimise binary pattern matching in
String.split/1andString.trim_*/1 - [Supervisor] Add
Supervisor.init/2andSupervisor.child_spec/2 - [Supervisor] Allow
moduleand{module, arg}to be given toSupervisor.start_link/2and invokemodule.child_spec(arg)on each argument - [Task] Support
:on_timeoutinTask.async_streamto control how tasks are terminated - [Task] Add
ordered: falsesupport toTask.async_stream
ExUnit
- [ExUnit] Show code snippet from test source file in case of test errors
- [ExUnit] Use
Exception.blame/3when formatting test errors - [ExUnit] Make
assert_raise/2fail if the underlying exception has a brokenmessage/1implementation - [ExUnit] Add
start_supervised/2andstop_supervised/1to ExUnit. Processes started by this function are automatically shut down when the test exits
IEx
- [IEx.Autocomplete] Support autocompletion of variable names
- [IEx.Autocomplete] Support autocompletion of functions imported using
import Mod, only: [...] - [IEx.Evaluator] Use
Exception.blame/3when showing errors in the terminal - [IEx.Helpers] Add
exports/1IEx helper to list all exports in a module - [IEx.Helpers] Add
break!/2,break!/4,breaks/0,continue/0,open/0,remove_breaks/0,remove_breaks/1,reset_break/1,reset_break/3andwhereami/1for code debugging - [IEx.Helpers] No longer emit warnings for IEx commands without parentheses
- [IEx.Helpers] Add
runtime_info/0for printing runtime system information - [IEx.Helpers] Add
open/1to open the source of a given module/function in your editor - [IEx.Info] Implement
IEx.Infoprotocol for calendar types
Logger
- [Logger] Add
metadata: :allconfiguration to log all metadata
Mix
- [mix compile.elixir] Add
--all-warningsoption to Elixir compiler that shows all warnings from the previous compilation (instead of just of the files being compiled) - [mix escript.build] Strip debug information from escripts by default and add option
:strip_beamwhich defaults to true - [mix loadpaths] Ensure
--no-deps-checkdo not trigger SCM callbacks (such asgit) - [mix local.hex] Add
--if-missingflag tolocal.hexmix task - [mix profile.cprof] Add
Mix.Tasks.Profile.Cproffor count-based profiling - [mix new] New styling for generated applications
2. Bug fixes
Elixir
- [Calendar] Ensure
Calendar.ISOraises a readable error when reaching up the year 10000 restriction - [Calendar] Return
{:error, :invalid_time}for wrong precision instead of crashing when parsing ISO dates - [Enumerable] Raise
Protocol.UndefinedErroron bad functions in Enumerable implementation - [File] Ensure recursive file operations raise on paths with null bytes (security issue reported by Griffin Byatt)
- [File] Support
:ram/:rawfiles inFile.copy/2 - [Inspect] Do not use colors when inspecting error messages
- [Kernel] Support guards on anonymous functions of zero arity
- [Kernel] Fix compilation of maps used as maps keys inside matches
- [Kernel] Ensure
doclause inwithis tail call optimizable - [Module]
on_definition/6callback receives body wrapped in a keyword list, such as[do: body]. This solves a bug where it was impossible to distinguish between a bodyless clause and a function that returnsnil. - [Path] Ensure recursive path operations raise on paths with null bytes (security issue reported by Griffin Byatt)
- [Protocol] Do not lose source compile info on protocol consolidation
- [Record] Properly escape quoted expressions passed to
defrecord - [Regex] Fix
inspect/2for regexes with/terminator in them - [Registry] Ensure
Registry.match/4works with:_as key - [Stream] Fix stream cycle over empty enumerable
- [String] Consider Unicode non-characters valid according to the specification in
String.valid?/1 - [StringIO] Fix encoding and performance issues in
StringIO.get_until - [System] Raise on paths with null bytes in
System.cmd/2and inSystem.find_executable/1(security issue reported by Griffin Byatt) - [System] Raise on ill-formed environment variables (security issue reported by Griffin Byatt)
ExUnit
- [ExUnit] Properly account failed tests when
setup_allfails - [ExUnit] Having two or more
describeblocks with the same name will now raise an error.
IEx
- [IEx] Skip autocompletion of module names that are invalid without being quoted
- [IEx] Skip autocompletion of functions with default arguments with
@doc false - [IEx] Do not start oldshell alongside IEx
Mix
- [mix compile.elixir] Store multiple sources in case of module conflicts. This solves an issue where
_buildwould get corrupted when compiling Elixir projects with module conflicts - [mix compile.erlang] Do not silently discard Erlang compile errors
- [mix compile.erlang] Properly track
-compilemodule attribute when specified as a list - [mix compile.protocols] Ensure protocol implementations do not "disappear" when switching between applications in umbrella projects by having separate consolidation paths per project
- [mix compile.protocols] Do not raise when consolidating a protocol that was converted into a module
3. Soft deprecations (no warnings emitted)
Elixir
- [Kernel]
not left in rightis soft-deprecated in favor ofleft not in right
4. Deprecations
Elixir
Atom.to_char_list/1,Float.to_char_list/1,Integer.to_char_list/1,Integer.to_char_list/2,Kernel.to_char_list/1,List.Chars.to_char_list/1,String.to_char_list/1have been deprecated in favor of theirto_charlistversion. This aligns with the naming conventions in both Erlang and Elixir- [Enum] Deprecate
Enum.filter_map/3in favor ofEnum.filter/2+Enum.map/2or for-comprehensions - [GenEvent] Deprecate
GenEventand provide alternatives in its docs - [Kernel] Using
()to meannilis deprecated - [Kernel]
:as_char_lists valueinInspect.Opts.t/0type, in favor of:as_charlists - [Kernel]
:char_listskey inInspect.Opts.t/0type, in favor of:charlists - [Module] Using Erlang parse transforms via
@compile {:parse_transform, _}is deprecated - [Stream] Deprecate
Stream.filter_map/3in favor ofStream.filter/2+Stream.map/2 - [String]
String.ljust/3andString.rjust/3are deprecated in favor ofString.pad_leading/3andString.pad_trailing/3with a binary padding - [String]
String.strip/1andString.strip/2are deprecated in favor ofString.trim/1andString.trim/2 - [String]
String.lstrip/1andString.rstrip/1are deprecated in favor ofString.trim_leading/1andString.trim_trailing/1 - [String]
String.lstrip/2andString.rstrip/2are deprecated in favor ofString.trim_leading/2andString.trim_trailing/2with a binary as second argument - [Typespec]
char_list/0type is deprecated in favor ofcharlist/0
EEx
- [EEx] Deprecate
<%=in "middle" and "end" expressions, e.g.:<%= else %>and<%= end %>
v1.4
The CHANGELOG for v1.4 releases can be found in the v1.4 branch.