|
1 | 1 | # Changelog for Elixir v1.19
|
2 | 2 |
|
| 3 | +## Type system improvements |
| 4 | + |
| 5 | +### More type inference |
| 6 | + |
| 7 | +Elixir now performs inference of whole functions. The best way to show the new capabilities are with examples. Take the following code: |
| 8 | + |
| 9 | +```elixir |
| 10 | +def add_foo_and_bar(data) do |
| 11 | + data.foo + data.bar |
| 12 | +end |
| 13 | +``` |
| 14 | + |
| 15 | +Elixir now infers that the function expects a `map` as first argument, and the map must have the keys `.foo` and `.bar` which values of either `integer()` or `float()`. The return type will be either `integer()` or `float()`. |
| 16 | + |
| 17 | +Here is another example: |
| 18 | + |
| 19 | +```elixir |
| 20 | +def sum_to_string(a, b) do |
| 21 | + Integer.to_string(a + b) |
| 22 | +end |
| 23 | +``` |
| 24 | + |
| 25 | +Even though the `+` operator works with both integers and floats, Elixir infers that `a` and `b` must be both integers, as the result of `+` is given to a function that expects an integer. The inferred type information is then used during type checking to find possible typing errors. |
| 26 | + |
| 27 | +### Type checking of protocol dispatch and implementations |
| 28 | + |
| 29 | +This release also adds type checking when dispatching and implementing protocols. |
| 30 | + |
| 31 | +For example, string interpolation in Elixir uses the `String.Chars` protocol. If you pass a value that does not implement said protocol, Elixir will now emit a warning accordingly. |
| 32 | + |
| 33 | +Here is an example passing a range, which cannot be converted into a string, to an interpolation: |
| 34 | + |
| 35 | +```elixir |
| 36 | +defmodule Example do |
| 37 | + def my_code(first..last//step = range) do |
| 38 | + "hello #{range}" |
| 39 | + end |
| 40 | +end |
| 41 | +``` |
| 42 | + |
| 43 | +the above emits the following warnings: |
| 44 | + |
| 45 | +``` |
| 46 | +warning: incompatible value given to string interpolation: |
| 47 | +
|
| 48 | + data |
| 49 | +
|
| 50 | +it has type: |
| 51 | +
|
| 52 | + %Range{first: term(), last: term(), step: term()} |
| 53 | +
|
| 54 | +but expected a type that implements the String.Chars protocol, it must be one of: |
| 55 | +
|
| 56 | + dynamic( |
| 57 | + %Date{} or %DateTime{} or %NaiveDateTime{} or %Time{} or %URI{} or %Version{} or |
| 58 | + %Version.Requirement{} |
| 59 | + ) or atom() or binary() or float() or integer() or list(term()) |
| 60 | +``` |
| 61 | + |
| 62 | +Warnings are also emitted if you pass a data type that does not implement the `Enumerable` protocol as a generator to for-comprehensions: |
| 63 | + |
| 64 | +```elixir |
| 65 | +defmodule Example do |
| 66 | + def my_code(%Date{} = date) do |
| 67 | + for(x <- date, do: x) |
| 68 | + end |
| 69 | +end |
| 70 | +``` |
| 71 | + |
| 72 | +will emit: |
| 73 | + |
| 74 | +``` |
| 75 | +warning: incompatible value given to for-comprehension: |
| 76 | +
|
| 77 | + x <- date |
| 78 | +
|
| 79 | +it has type: |
| 80 | +
|
| 81 | + %Date{year: term(), month: term(), day: term(), calendar: term()} |
| 82 | +
|
| 83 | +but expected a type that implements the Enumerable protocol, it must be one of: |
| 84 | +
|
| 85 | + dynamic( |
| 86 | + %Date.Range{} or %File.Stream{} or %GenEvent.Stream{} or %HashDict{} or %HashSet{} or |
| 87 | + %IO.Stream{} or %MapSet{} or %Range{} or %Stream{} |
| 88 | + ) or fun() or list(term()) or non_struct_map() |
| 89 | +``` |
| 90 | + |
3 | 91 | ## v1.19.0-dev
|
4 | 92 |
|
5 | 93 | ### 1. Enhancements
|
6 | 94 |
|
7 | 95 | #### Elixir
|
8 | 96 |
|
9 | 97 | * [Code] Add `:migrate_call_parens_on_pipe` formatter option
|
| 98 | + * [Date] Support durations as the second element in `Date.range/3` |
| 99 | + * [Enum] Provide more information on `Enum.OutOfBoundsError` |
10 | 100 | * [Kernel] Support `min/2` and `max/2` as guards
|
| 101 | + * [Protocol] Type checking of protocols dispatch and implementations |
| 102 | + * [Protocol] Add `Protocol.impl_for/2` and `Protocol.impl_for!/2` |
11 | 103 |
|
12 | 104 | #### IEx
|
13 | 105 |
|
14 | 106 | * [IEx.Autocomplete] Functions annotated with `@doc group: "Name"` metadata will appear within their own groups in autocompletion
|
15 | 107 |
|
| 108 | +#### Mix |
| 109 | + |
| 110 | + * [Mix.Tasks.Compile] Add `Mix.Tasks.Compile.reenable/1` |
| 111 | + |
16 | 112 | ### 2. Bug fixes
|
17 | 113 |
|
| 114 | +#### Mix |
| 115 | + |
| 116 | + * [mix cmd] Preserve argument quoting in subcommands |
| 117 | + |
18 | 118 | ### 3. Soft deprecations (no warnings emitted)
|
19 | 119 |
|
20 | 120 | #### Elixir
|
|
33 | 133 | * [Code] The `on_undefined_variable: :warn` is deprecated. Relying on undefined variables becoming function calls will not be supported in the future
|
34 | 134 | * [File] Passing a callback as third argument to `File.cp/3` is deprecated, pass it as a `on_conflict: callback` option instead
|
35 | 135 | * [File] Passing a callback as third argument to `File.cp_r/3` is deprecated, pass it as a `on_conflict: callback` option instead
|
| 136 | + * [Kernel] The struct update syntax, such as `%URI{uri | path: "/foo/bar"}` is deprecated in favor of pattern matching on the struct when the variable is defined and then using the map update syntax `%{uri | path: "/foo/bar"}`. Thanks to the type system, pattern matching on structs can find more errors, more reliably |
36 | 137 | * [Kernel.ParallelCompiler] Passing `return_diagnostics: true` as an option is required on `compile`, `compile_to_path` and `require`
|
37 | 138 |
|
38 | 139 | #### Logger
|
|
0 commit comments