Compare commits
7
Commits
v1.11.4
...
v1.8.0-rc.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b59405756 | ||
|
|
4231a62c67 | ||
|
|
35e7c8c38c | ||
|
|
8e4d718b93 | ||
|
|
3ad9193b4b | ||
|
|
d655a2884e | ||
|
|
5529c5fa4e |
+77
-2
@@ -1,6 +1,69 @@
|
||||
# Changelog for Elixir v1.8
|
||||
|
||||
## v1.8.0-dev
|
||||
Elixir v1.8 comes with many improvements at the infrastructure level, improving compilation time, speeding up common patterns, and adding features around introspection of the system.
|
||||
|
||||
## Custom struct inspections
|
||||
|
||||
Elixir now provides a derivable implementation of the `Inspect` protocol. In a nutshell, this means it is really easy to filter data from your data structures whenever they are inspected. For example, imagine you have a user struct with security and privacy sensitive information:
|
||||
|
||||
```elixir
|
||||
defmodule User do
|
||||
defstruct [:id, :name, :age, :email, :encrypted_password]
|
||||
end
|
||||
```
|
||||
|
||||
By default, if you inspect a user via `inspect(user)`, it will include all fields. This can cause fields such as `:email` and `:encrypted_password` to appear in logs, error reports, etc. You could always define a custom implementation of the `Inspect` protocol for such cases but Elixir v1.8 makes it simpler by allowing you to derive the `Inspect` protocol:
|
||||
|
||||
```elixir
|
||||
defmodule User do
|
||||
@derive {Inspect, only: [:id, :name, :age]}
|
||||
defstruct [:id, :name, :age, :email, :encrypted_password]
|
||||
end
|
||||
```
|
||||
|
||||
Now all user structs will be printed with all remaining fields collapsed:
|
||||
|
||||
#User<id: 1, name: "Jane", age: 33, ...>
|
||||
|
||||
You can also pass `@derive {Inspect, except: [...]}` in case you want to keep all fields by default and exclude only some.
|
||||
|
||||
## Time zone database support
|
||||
|
||||
In Elixir v1.3, Elixir added four types, known as Calendar types, to work with dates and times: `Time`, `Date`, `NaiveDateTime` (without time zone) and `DateTime` (with time zone). Over the last releases we have added many enhancements to the Calendar types but the `DateTime` module always evolved at a slower pace since Elixir did not provide support for a time zone database.
|
||||
|
||||
Elixir v1.8 now defines a `Calendar.TimeZoneDatabase` behaviour, allowing developers to bring in their own time zone databases. By defining an explicit contract for time zone behaviours, Elixir can now extend the `DateTime` API, adding functions such as `DateTime.shift_zone/3`. By default, Elixir ships with a time zone database called `Calendar.UTCOnlyTimeZoneDatabase` that only handles UTC.
|
||||
|
||||
Other Calendar related improvements include the addition of `Date.day_of_year/1`, `Date.quarter_of_year/1`, `Date.year_of_era/1`, and `Date.day_of_era/1`.
|
||||
|
||||
## Faster compilation and other performance improvements
|
||||
|
||||
Due to improvements to the compiler made over the last year, Elixir v1.8 should compile code about 5% faster on average. This is yet another release where we have been able to reduce compilation times and provide a more joyful development experience to everyone.
|
||||
|
||||
The compiler also emits more efficient code for range checks in guards (such as `x in y..z`), for charlists with interpolation (such as `'foo #{bar} baz'`), and when working with records via the `Record` module.
|
||||
|
||||
Finally, EEx templates got their own share of optimizations, emitting more compact code that runs faster.
|
||||
|
||||
## Improved instrumentation and ownership with `$callers`
|
||||
|
||||
The `Task` module is one of the most common ways to spawn light-weight processes to perform work concurrently. Whenever you spawn a new process, Elixir annotates the parent of that process through the `$ancestors` key. This information can be used by instrumentation tools to track the relationship between events occurring within multiple processes. However, many times, tracking only the `$ancestors` is not enough.
|
||||
|
||||
For example, we recommend developers to always start tasks under a supervisor. This provides more visibility and allows us to control how those tasks are terminated when a node shuts down. In your code, this can be done by invoking something like: `Task.Supervisor.start_child(MySupervisor, task_specification)`. This means that, although your code is the one who invokes the task, the actual parent of the task would be the supervisor, as the supervisor is the one spawning it. We would list the supervisor as one of the `$ancestors` for the task, but the relationship between your code and the task is lost.
|
||||
|
||||
In Elixir v1.8, we now track the relationship between your code and the task via the `$callers` key in the process dictionary, which aligns well with the existing `$ancestors` key. Therefore, assuming the `Task.Supervisor` call above, we have:
|
||||
|
||||
[your code] -- calls --> [supervisor] ---- spawns --> [task]
|
||||
|
||||
which means we store the following relationships:
|
||||
|
||||
[your code] [supervisor] <-- ancestor -- [task]
|
||||
^ |
|
||||
|--------------------- caller ---------------------|
|
||||
|
||||
When a task is spawned directly from your code, without a supervisor, then the process running your code will be listed under both `$ancestors` and `$callers`.
|
||||
|
||||
This small feature is very powerful. It allows instrumentation and monitoring tools to better track and relate the events happening in your system. This feature can also be used by tools like the "Ecto Sandbox". The "Ecto Sandbox" allows developers to run tests concurrently against the database, by using transactions and an ownership mechanism where each process explicitly gets a connection assigned to it. Without `$callers`, every time you spawned a task that queries the database, the task would not know its caller, and therefore it would be unable to know which connection was assigned to it. This often meant features that relies on tasks could not be tested concurrently. With `$callers`, figuring out this relationship is trivial and you have more tests using the full power of your machine.
|
||||
|
||||
## v1.8.0-rc.0 (2018-12-24)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -23,12 +86,15 @@
|
||||
* [Kernel] Add `:delegate_to` `@doc` metadata tag when using `defdelegate`
|
||||
* [Kernel] Improve compile-time building of ranges via the `..` operator
|
||||
* [Kernel] Compile charlist interpolation more efficiently
|
||||
* [Kernel.SpecialForms] Add `:reduce` option to `for` comprehensions
|
||||
* [List] Add `List.myers_difference/3` and `List.improper?/1`
|
||||
* [Macro] Add `Macro.struct!/2` for proper struct resolution during compile time
|
||||
* [Map] Optimize and merge nested maps `put` and `merge` operations
|
||||
* [Range] Add `Range.disjoint?/2`
|
||||
* [Record] Reduce memory allocation when updating multiple fields in a record
|
||||
* [Registry] Allow associating a value on `:via` tuple
|
||||
* [String] Add `String.bag_distance/2`
|
||||
* [Task] Add `$callers` tracking to `Task` - this makes it easier to find which process spawned a task and use it for tracking ownership and monitoring
|
||||
|
||||
#### ExUnit
|
||||
|
||||
@@ -58,19 +124,26 @@
|
||||
* [Calendar] Allow printing dates with more than 9999 years
|
||||
* [Exception] Exclude deprecated functions in "did you mean?" hints
|
||||
* [Float] Handle subnormal floats in `Float.ratio/1`
|
||||
* [Kernel] Remove `Guard test tuple_size(...) can never succeed` dialyzer warning on try
|
||||
* [Kernel] Remove `Guard test tuple_size(...) can never succeed` Dialyzer warning on `try`
|
||||
* [Kernel] Expand operands in `size*unit` bitstring modifier instead of expecting `size` and `unit` to be literal integers
|
||||
* [Kernel] Do not deadlock on circular struct dependencies in typespecs
|
||||
* [Kernel] Raise proper error message when passing flags to the Erlang compiler that Elixir cannot handle
|
||||
* [Kernel] Do not leak variables in `cond` clauses with a single matching at compile-time clause
|
||||
* [NaiveDateTime] Do not accept leap seconds in builder and parsing functions
|
||||
* [String] Fix ZWJ handling in Unicode grapheme clusters
|
||||
|
||||
#### IEx
|
||||
|
||||
* [IEx.Helpers] Use typespec info (instead of docs chunk) and properly format callbacks in `b/1`
|
||||
|
||||
#### Logger
|
||||
|
||||
* [Logger] Allow Logger backends to be dynamically removed when an application is shutting down
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix compile] Ensure changes in deps propagate to all umbrella children - this fix a long standing issue where updating a dependency would not recompile all projecys accordingly, requiring a complete removal of `_build`
|
||||
* [mix compile] Avoid time drift when checking and updating compiler manifest files
|
||||
* [mix compile.app] Respect the `:only` option between umbrella siblings
|
||||
* [mix compile.protocols] Reconsolidate protocols if local dependencies are stale
|
||||
* [mix deps] Properly mark dependencies with different `:system_env` as diverged
|
||||
@@ -78,6 +151,8 @@
|
||||
|
||||
### 3. Soft-deprecations (no warnings emitted)
|
||||
|
||||
None.
|
||||
|
||||
### 4. Hard-deprecations
|
||||
|
||||
#### Elixir
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PREFIX ?= /usr/local
|
||||
SHARE_PREFIX ?= $(PREFIX)/share
|
||||
MAN_PREFIX ?= $(SHARE_PREFIX)/man
|
||||
CANONICAL := master/ # master/ or vMAJOR.MINOR/
|
||||
CANONICAL := v1.8/ # master/ or vMAJOR.MINOR/
|
||||
ELIXIRC := bin/elixirc --verbose --ignore-module-conflict --warnings-as-errors
|
||||
ERLC := erlc -I lib/elixir/include +warnings_as_errors
|
||||
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
|
||||
|
||||
+19
-10
@@ -4567,10 +4567,17 @@ defmodule Kernel do
|
||||
|
||||
Any protocol module contains three extra functions:
|
||||
|
||||
* `__protocol__/1` - returns the protocol name when `:name` is given, a
|
||||
keyword list with the protocol functions and their arities when
|
||||
`:functions` is given, and a list of the implementations when `:impls` is
|
||||
given
|
||||
* `__protocol__/1` - returns the protocol information. The function takes
|
||||
one of the following atoms:
|
||||
|
||||
* `:consolidated?` - returns whether the protocol is consolidated
|
||||
|
||||
* `:functions` - returns keyword list of protocol functions and their arities
|
||||
|
||||
* `:impls` - if consolidated, returns `{:consolidated, modules}` with the list of modules
|
||||
implementing the protocol, otherwise `:not_consolidated`
|
||||
|
||||
* `:module` - the protocol module atom name
|
||||
|
||||
* `impl_for/1` - receives a structure and returns the module that
|
||||
implements the protocol for the structure, `nil` otherwise
|
||||
@@ -4578,14 +4585,16 @@ defmodule Kernel do
|
||||
* `impl_for!/1` - same as above but raises an error if an implementation is
|
||||
not found
|
||||
|
||||
Enumerable.__protocol__(:functions)
|
||||
#=> [count: 1, member?: 2, reduce: 3]
|
||||
For example, for the `Enumerable` protocol we have:
|
||||
|
||||
Enumerable.impl_for([])
|
||||
#=> Enumerable.List
|
||||
iex> Enumerable.__protocol__(:functions)
|
||||
[count: 1, member?: 2, reduce: 3, slice: 1]
|
||||
|
||||
Enumerable.impl_for(42)
|
||||
#=> nil
|
||||
iex> Enumerable.impl_for([])
|
||||
Enumerable.List
|
||||
|
||||
iex> Enumerable.impl_for(42)
|
||||
nil
|
||||
|
||||
## Consolidation
|
||||
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
defmodule OptionParser do
|
||||
@moduledoc """
|
||||
This module contains functions to parse command line options.
|
||||
Functions for parsing command line options.
|
||||
|
||||
The main function in this module is `parse/2`, which allows
|
||||
developers to parse a list of arguments into options:
|
||||
|
||||
iex> OptionParser.parse(["--debug"], strict: [debug: :boolean])
|
||||
{[debug: true], [], []}
|
||||
|
||||
`OptionParser` provides some conveniences out of the box,
|
||||
such as aliases and automatic handling of negation switches.
|
||||
|
||||
The `parse_head/2` function is an alternative to `parse/2`
|
||||
which stops parsing as soon as it finds a value that is not
|
||||
a switch nor a value for a previous switch.
|
||||
|
||||
This module also provides low-level functions, such as `next/2`,
|
||||
for parsing switches manually, as well as `split/1` and `to_argv/1`
|
||||
for parsing from and converting switches to strings.
|
||||
"""
|
||||
|
||||
@type argv :: [String.t()]
|
||||
@@ -65,10 +82,9 @@ defmodule OptionParser do
|
||||
* `:switches` - defines some switches and their types. This function
|
||||
still attempts to parse switches that are not in this list.
|
||||
|
||||
Both these options accept a keyword list of `{name, type}` tuples where `name`
|
||||
is an atom defining the name of the switch and `type` is an atom that
|
||||
specifies the type for the value of this switch (see the "Types" section below
|
||||
for the possible types and more information about type casting).
|
||||
Both these options accept a keyword list where the key is an atom
|
||||
defining the name of the switch and value is the `type` of the
|
||||
switch (see the "Types" section below for more information).
|
||||
|
||||
Note that you should only supply the `:switches` or the `:strict` option.
|
||||
If you supply both, an `ArgumentError` exception will be raised.
|
||||
|
||||
@@ -8,11 +8,11 @@ Elixir applies bug fixes only to the latest minor branch. Security patches are a
|
||||
|
||||
Elixir version | Support
|
||||
:------------- | :-----------------------------
|
||||
1.7 | Bug fixes and security patches
|
||||
1.8 | Bug fixes and security patches
|
||||
1.7 | Security patches only
|
||||
1.6 | Security patches only
|
||||
1.5 | Security patches only
|
||||
1.4 | Security patches only
|
||||
1.3 | Security patches only
|
||||
|
||||
New releases are announced in the read-only [announcements mailing list](https://groups.google.com/group/elixir-lang-ann). All security releases [will be tagged with `[security]`](https://groups.google.com/forum/#!searchin/elixir-lang-ann/%5Bsecurity%5D%7Csort:date).
|
||||
|
||||
@@ -50,6 +50,7 @@ Elixir version | Supported Erlang/OTP versions
|
||||
1.5 | 18 - 20
|
||||
1.6 | 19 - 20 (and Erlang/OTP 21 from v1.6.6)
|
||||
1.7 | 19 - 21
|
||||
1.8 | 20 - 21
|
||||
|
||||
While Elixir often adds compatibility to new Erlang/OTP versions on released branches, such as support for Erlang/OTP 20 in v1.4.5, those releases usually contain the minimum changes for Elixir to run without errors. Only the next minor release, in this case v1.5.0, does effectively leverage the new features provided by the latest Erlang/OTP release.
|
||||
|
||||
@@ -148,4 +149,4 @@ Non-map as second argument in `URI.decode_query/2` | [v1.3] | Use a map (v1
|
||||
[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations
|
||||
[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations
|
||||
[v1.7]: https://github.com/elixir-lang/elixir/blob/v1.7/CHANGELOG.md#4-hard-deprecations
|
||||
[v1.8]: https://github.com/elixir-lang/elixir/blob/master/CHANGELOG.md#4-hard-deprecations
|
||||
[v1.8]: https://github.com/elixir-lang/elixir/blob/v1.8/CHANGELOG.md#4-hard-deprecations
|
||||
|
||||
@@ -533,31 +533,31 @@ defmodule ExceptionTest do
|
||||
test "annotates band arithmetic errors" do
|
||||
use Bitwise
|
||||
|
||||
assert blame_message(:foo, &band(10, &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.band(10, :foo)"
|
||||
assert blame_message(:foo, &band(&1, 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.band(:foo, 10)"
|
||||
|
||||
assert blame_message(:foo, &(10 &&& &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.band(10, :foo)"
|
||||
assert blame_message(:foo, &(&1 &&& 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.band(:foo, 10)"
|
||||
end
|
||||
|
||||
test "annotates bor arithmetic errors" do
|
||||
use Bitwise
|
||||
|
||||
assert blame_message(:foo, &bor(10, &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bor(10, :foo)"
|
||||
assert blame_message(:foo, &bor(&1, 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bor(:foo, 10)"
|
||||
|
||||
assert blame_message(:foo, &(10 ||| &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bor(10, :foo)"
|
||||
assert blame_message(:foo, &(&1 ||| 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bor(:foo, 10)"
|
||||
end
|
||||
|
||||
test "annotates bxor arithmetic errors" do
|
||||
use Bitwise
|
||||
|
||||
assert blame_message(:foo, &bxor(10, &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bxor(10, :foo)"
|
||||
assert blame_message(:foo, &bxor(&1, 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bxor(:foo, 10)"
|
||||
|
||||
assert blame_message(:foo, &(10 ^^^ &1)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bxor(10, :foo)"
|
||||
assert blame_message(:foo, &(&1 ^^^ 10)) ==
|
||||
"bad argument in arithmetic expression: Bitwise.bxor(:foo, 10)"
|
||||
end
|
||||
|
||||
test "annotates bsl arithmetic errors" do
|
||||
|
||||
Reference in New Issue
Block a user