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

Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
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
New
axelson
Decided against including more info in the title, but the gist is that Plataformatec sponsored projects will continue with the assets bei...
New
New
sergio
There’s a new TIOBE index report that came out that shows Elixir is still not in the top 50 used languages. It also goes on to call Elix...
New
AstonJ
If a newbie asked you about Phoenix Contexts, how would you explain the basics to them? Feel free to be as concise or in-depth as you li...
New
acrolink
How does the two languages compare when it comes to server side application development? Any experiences or ideas? Thank you.
New
scouten
I’m looking for a host for the server part of a small (personal) side project that I’m working on. It’s currently written in Node.js and ...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29305 241
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I fore...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement