Crowdhailer

Crowdhailer

Creator of Raxx

Semantic pattern matching, useful or not?

It is rare to use direct calls to send in elixir. The call is normally wrapped in a function which is responsible for sending the correct message. The most common example of this has to be GenServer.call. This is seen as good practice as it allows the structure of the message to be hidden. The structure of the message being an implementation detail only.

However when receiving a message or pattern matching the internal details must always be known. At least this is certainly true in erlang but does not need to be true in Elixir because it has macros.

The most simple case I can think of is the convention of using {:ok, value} || {:error, reason}. This is an implementation of how a function can indicate it has succeeded or failed. It would be possible to use another convention for example %Try.Success{value: value} || %Try.Failure{reason: reason}. To hide which implementation is being used macros can be employed. E.g in a case statement. (The same is true in a receive block).

For example.

case my_func() do
  {:ok, value} ->
    # continue
  {:error, reason} ->
    # report error
end

can be replaced with what I call “semantic pattern matching”

case my_func() do
  success(value) ->
    # continue
  failure(reason) ->
    # report error
end

An implementation of the success and fail macros is available in my OK project.

I will admit that the extra value in this case might not be very high. The example of :ok/:error tuples is both simple and common knowledge. However I think it could be very useful in a few cases, for example.

  • When a process could receive messages from two different libraries. e.g. a Gen server that is running taskes. It might receive a call message or a message notifying of a completed task.
  • A finite statemachine that is receiving commands to change state.

Most Liked

josevalim

josevalim

Creator of Elixir

For what is worth, this is a question I frequently ask myself: if it is worth adding abstractions on top of pattern matching and provide conveniences such as defpattern and/or defguard? It is one of those things I am somewhat glad the Erlang VM restrict us from generalizing because we would probably have done so some time ago and the solution may not have been ideal.

Maybe one day we will add something that resembles discriminated unions and named patterns, which would give the features you described above, but right now there are still many questions around on how to generalize such patterns while providing good performance and sane semantics. The current mechanism, although it may be repetitive some times, it is simple, explicit and straight-forward. See the expat thread for a similar discussion.

11
Post #4
X4lldux

X4lldux

I’ve created a library for doing exactly this, called disc_union. For your example it would look like this:

defmodule Result do
  use DiscUnion

  defunion :ok in any() | :error in atom
end

defmodule Example do
   use Result

   def foo() do
     Result.case my_func() do # expects a %Result{} struct
       :ok in value -> #continues
       :error in reason -> #report the error
     end
   end
end

NOTE: you can also “import” a regular error tuple into the Result struct using Result.from!/1 function and it will check if what your are importing was defined as one of the variants.

Downside is that for each discriminated union there has to be a specially created case macro, in order for it to “know” what valid variants are in this union and warn you (at compile time) when you miss one or implement it with a wrong shape. I find it very useful and use it in production even though I still consider this a research project.

Qqwy

Qqwy

TypeCheck Core Team

I believe that if your patterns become too complex in a single function, then that might be a very clear indicator that that function could be split in smaller parts.

I do like pattern-matching extensively to ensure that people know it right away when they put garbage in my libraries’ functions. Sometimes these matches become relatively long. I have been tempted to fiddle with pattern-providing macros before, but have not gone through with it until now because I also believed that this would make it harder to read what was going on. I think there are some use cases where you frequently want to match a struct that is in a certain state.

I agree with @josevalim and @crowdhailer: This is not something Elixir itself should provide, but it is great that we can, if it turns out to be useful for the project at hand, write macros that do this stuff.

X4lldux

X4lldux

Like in the tennis kata example where a PlayerPoints.case macro “understands” what it’s possible variants are - which are defined at line 13 - and programmer needs to explicitly cover all of them.

It’s basically a discriminated union concept, and even though a Elixir is a dynamic language, this library gives some compile-time warnings.

minhajuddin

minhajuddin

Pattern matching is one of the best superpowers that erlang/elixir have. We should not try to decorate/hide pattern matching with other stuff by adding more magic. I agree that having more expressive atoms may be helpful, but this may not be the best way to go about it, See Usage of {:ok, result} / :error vs {:some, result} / :none . To me it seems like we are adding more noise without giving the user much in return.

Where Next?

Popular in Discussions Top

f0rest8
Hi everyone :waving_hand: Posting here to showcase and announce that Metamorphic is now officially live on a public-facing domain at htt...
New
jeramyRR
Is it really necessary for the compiler to spit out a warning about using @doc with private functions? I don’t want to have to document ...
New
AstonJ
Inspired by @dogweather’s thread about Active Record Doctor, have you seen any impressive or cool things in other non-BEAM languages or f...
New
christopheradams
I was recently asked to step up and become the maintainer for the Elixir Style Guide. It was, I believe, the first, and is now the most p...
New
stevensonmt
Has anyone else ever wanted to merge two maps, but have the resulting map only include keys common to both maps? I think of it as analogo...
New
James_E
I see that the current ExUnit source code has support for rich failure messages on a small whitelist of “recognized” assertion patterns, ...
New
bartblast
Some great comments in the home page thread shifted toward what you’d like to see in Hologram’s future, particularly standalone mode. I’v...
New
bartblast
Added by a user on X: https://x.com/aldicodes/status/1952095492139299036
New
paulanthonywilson
I like Umbrella projects and pretty much always use them for personal Elixir stuff, especially Nerves things. But I don’t think this is ...
New
kusokuzeshiki
I tried to generate pages with claude code and fluxon ui. I ask to claude code to generate real world page samples, the results are thes...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New

We're in Beta

About us Mission Statement