ilya-kolpakov

ilya-kolpakov

Structs: pattern matching on nil values

I think the behavior of pattern matching on null-valued pairs within structs is surprising:

iex(6)> defmodule A do defstruct [:a, :b] end
iex(7)> match?(%A{a: a}, %A{})               
true
iex(8)> match?(%{a: a}, %{})  
false

I would argue this is not very useful. By matching on the struct itself (e.g. on %A{}) we already know the keys that are going to be present. Hence pattern-matching on members provides zero additional value.

IMO, it would be more useful if the above struct match returned false. Indeed, it would provide a way to test a semantical presence of a value rather than a mechanical one. This can be done via guards but the syntax is more verbose.

Most Liked

michalmuskala

michalmuskala

This is not true. At least not on today’s BEAM. Matching on <<_:binary>> is going to be faster, if you’re doing a binary pattern match already, to keep the “single match context” optimization. But if you’re only checking if something is a binary, it’s going to be slower. This is primarily because it needs to allocate the match context (which creates garbage on the heap that will lead to sooner garbage collection), while checking is_binary does not involve any memory movements. This memory access (and GC jitter) can be seen in the increased deviation of the benchmark.

Operating System: macOS
CPU Information: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
Number of Available Cores: 8
Available memory: 16 GB
Elixir 1.6.0-dev
Erlang 20.1
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
parallel: 1
inputs: binary, not binary
Estimated total run time: 28 s

##### With input binary #####
Name            ips        average  deviation         median         99th %
guard      436.27 K        2.29 μs    ±34.28%        2.10 μs        4.20 μs
match      236.41 K        4.23 μs  ±1391.73%           4 μs          11 μs

Comparison:
guard      436.27 K
match      236.41 K - 1.85x slower

##### With input not binary #####
Name            ips        average  deviation         median         99th %
guard      448.69 K        2.23 μs    ±35.38%           2 μs        4.40 μs
match      431.08 K        2.32 μs    ±43.81%        2.20 μs        4.60 μs

Comparison:
guard      448.69 K
match      431.08 K - 1.04x slower

The benchmark code:

defmodule Bench do
  def match(<<_::binary>>), do: :binary
  def match(_), do: :not_binary

  def guard(binary) when is_binary(binary), do: :binary
  def guard(_), do: :not_binary

  def loop(0, _fun) do
    :ok
  end
  def loop(n, fun) do
    fun.()
    loop(n - 1, fun)
  end
end

jobs = %{
  "match" => fn input -> Bench.loop(100, fn -> Bench.match(input) end) end,
  "guard" => fn input -> Bench.loop(100, fn -> Bench.guard(input) end) end
}

inputs = %{
  "binary" => "foo",
  "not binary" => 123
}

Benchee.run(jobs, inputs: inputs)
benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

It provides tons of value if you include a pattern on those members, or if you include those members in a guard.

Let’s filter all As that are empty

as |> Enum.filter(&match?(%A{a: []}, &1))

Ultimately the whole point of match? is that it works exactly like:

case value do
  %A{a: a} -> true
  _ -> false
end

If you want some other characteristic then you want some other function.

We are more than happy to try to help provide the most idiomatic way to achieve whatever your goal is in this situation. Just understand that suggestions that involve breaking changes to core functions are unlikely to gain a lot of traction.

idi527

idi527

Or !!%A{}.a … looks a bit like swearing.

Where Next?

Popular in Discussions Top

Rustixir
Hi everyone, im working on find best language/framework/system for high concurrency, high performance and stable performance after wor...
New
arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New
ricklove
I was just introduced to Elixir and Phoenix. I was told about the 2 million websocket test that was done 2 years ago. From my research, t...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
WolfDan
After doing a port from a c++ library to my project in phoenix I’ve seen that I need a faster way to run this algorithm and I found this ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
New
CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -&gt; H; nth(N, [_|T]) when N &gt; 1 -&gt; nth(N - 1, T). Elixir Enum.at … coo...
New
ben-pr-p
In general I’ve been sticking to this community style guide GitHub - christopheradams/elixir_style_guide: A community driven style guide ...
New
New

Other popular topics Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41454 115
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30840 112
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New

We're in Beta

About us Mission Statement