From 7bf19685a0509511e3ab8271f54cfdff9e0aac88 Mon Sep 17 00:00:00 2001 From: Andrea leopardi Date: Thu, 2 Jun 2022 14:20:34 +0200 Subject: [PATCH 1/3] Add remaining info for 1.14 CHANGELOG --- CHANGELOG.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4166b00085..dd5fe09d129 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,15 +79,85 @@ Task.Supervisor.async( ## Improved errors on binaries and evaluation -TODO. +OTP 25 improved errors on binary construction and evaluation. These improvements +apply to Elixir as well. Before v1.14, errors when constructing binaries would +often be hard-to-debug generic "argument errors". With OTP 25 and Elixir v1.14, +more detail is provided for easier debugging. This work is part of [EEP +54](https://www.erlang.org/eeps/eep-0054). + +```elixir +# Before: +int = 1 +bin = "foo" +int <> bin +# ** (ArgumentError) argument error + +# Now: +int = 1 +bin = "foo" +int <> bin +# ** (ArgumentError) construction of binary failed: +# segment 1 of type 'binary': +# expected a binary but got: 1 +``` ## Slicing with steps -TODO. +Elixir v1.12 introduced **stepped ranges**, which are ranges where you can +specify the "step": + +```elixir +Enum.to_list(1..10//3) +#=> [1, 4, 7, 10] +``` + +Stepped ranges are particularly useful for numerical operations involving +vectors and matrices (see [Nx](https://github.com/elixir-nx/nx), for example). +However, the Elixir standard library was not making use of stepped ranges in its +APIs. Elixir v1.14 starts to take advantage of steps with support for stepped +ranges in `Enum.slice/2`: + +```elixir +letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"] +Enum.slice(integers, 0..5//2) +#=> ["a", "c", "e"] +``` ## Expression-based inspection -TODO. +In Elixir, it's conventional to implement the `Inspect` protocol for structs so +that they're inspected with a syntax resembling this: + +```elixir +IO.inspect(Version.parse("1.0.0")) +#=> {:ok, #Version<1.0.0>} +``` + +This is generally done when the struct content or part of it is private and the +`%Version{...}` representation would reveal fields that are not part of the +public API. + +The downside of the `#name<...>` convention is that *the inspected output is not +valid Elixir code*. You cannot do things such as copying the inspected output +and pasting it into an IEx session or similar. + +Elixir v1.14 changes the convention for some of the standard-library structs. +The `Inspect` implementation for those structs is now a string with a valid +Elixir expression that recreates the struct itself if evaluated. In the +`Version` example above, this is what we have now: + +```elixir +IO.inspect(Version.parse("1.0.0")) +#=> {:ok, Version.parse!("1.0.0")} +``` + +The `Version.parse/1` expression evaluates to exactly the struct that we're +inspecting. + +This expression-based inspection has been implemented for `Version`, +`Version.Requirement`, `MapSet`, and `Date.Range`. Other data types (such as +`PID`) still use the `#name<...>` convention because generally there is no +Elixir expression that can deterministically recreate the data type. ## v1.14.0-dev From f95933198c4193c953c14e9e377be414e00e5537 Mon Sep 17 00:00:00 2001 From: Andrea leopardi Date: Fri, 3 Jun 2022 09:19:01 +0200 Subject: [PATCH 2/3] FIXUP --- CHANGELOG.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd5fe09d129..ea848f77938 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -115,27 +115,34 @@ Stepped ranges are particularly useful for numerical operations involving vectors and matrices (see [Nx](https://github.com/elixir-nx/nx), for example). However, the Elixir standard library was not making use of stepped ranges in its APIs. Elixir v1.14 starts to take advantage of steps with support for stepped -ranges in `Enum.slice/2`: +ranges in a couple of functions. One of them is `Enum.slice/2`: ```elixir letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"] -Enum.slice(integers, 0..5//2) +Enum.slice(letters, 0..5//2) #=> ["a", "c", "e"] ``` +Another one is `binary_slice/2` in the `Kernel` module: + +```elixir +binary_slice("Elixir", 1..5//2) +#=> "lx" +``` + ## Expression-based inspection In Elixir, it's conventional to implement the `Inspect` protocol for structs so that they're inspected with a syntax resembling this: ```elixir -IO.inspect(Version.parse("1.0.0")) -#=> {:ok, #Version<1.0.0>} +MapSet.new([:apple, :banana]) +#MapSet<[:apple, :banana]> ``` This is generally done when the struct content or part of it is private and the -`%Version{...}` representation would reveal fields that are not part of the -public API. +`%name{...}` representation would reveal fields that are not part of the public +API. The downside of the `#name<...>` convention is that *the inspected output is not valid Elixir code*. You cannot do things such as copying the inspected output @@ -147,11 +154,12 @@ Elixir expression that recreates the struct itself if evaluated. In the `Version` example above, this is what we have now: ```elixir -IO.inspect(Version.parse("1.0.0")) -#=> {:ok, Version.parse!("1.0.0")} +fruits = MapSet.new([:apple, :banana]) +MapSet.put(fruits, :pear) +#=> MapSet.new([:apple, :banana, :pear]) ``` -The `Version.parse/1` expression evaluates to exactly the struct that we're +The `MapSet.new/1` expression evaluates to exactly the struct that we're inspecting. This expression-based inspection has been implemented for `Version`, From 8631158900b84b44cd8dfa8db4092d5081a406ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 3 Jun 2022 23:24:12 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Eksperimental --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea848f77938..81b79082380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -79,9 +79,9 @@ Task.Supervisor.async( ## Improved errors on binaries and evaluation -OTP 25 improved errors on binary construction and evaluation. These improvements +Erlang/OTP 25 improved errors on binary construction and evaluation. These improvements apply to Elixir as well. Before v1.14, errors when constructing binaries would -often be hard-to-debug generic "argument errors". With OTP 25 and Elixir v1.14, +often be hard-to-debug generic "argument errors". With Erlang/OTP 25 and Elixir v1.14, more detail is provided for easier debugging. This work is part of [EEP 54](https://www.erlang.org/eeps/eep-0054). @@ -90,15 +90,15 @@ more detail is provided for easier debugging. This work is part of [EEP int = 1 bin = "foo" int <> bin -# ** (ArgumentError) argument error +#=> ** (ArgumentError) argument error # Now: int = 1 bin = "foo" int <> bin -# ** (ArgumentError) construction of binary failed: -# segment 1 of type 'binary': -# expected a binary but got: 1 +#=> ** (ArgumentError) construction of binary failed: +#=> segment 1 of type 'binary': +#=> expected a binary but got: 1 ``` ## Slicing with steps