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

New
fklement
This is a thread to gather some information about the efforts of using elixir in combination with cars or vehicular systems in general. ...
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
smueller
With the announcement of 1.19 rc0 and the path to user-supplied type annotations, I want to make the case for inline types—both for funct...
New
AstonJ
@Garrison’s comment in another thread reminded me of this post by Joe: With the big five exerting more control than ever, new (AI) play...
New
billylanchantin
If you’re not familiar with this fun bit of math lore, Paul Erdős, the famously eccentric, peripatetic and prolific 20th-century mathem...
New
ashkan117
I’m wondering how do people structure their JSON Api’s with Phoenix. Using the blogs example, let’s say I have a blogs view like the foll...
New
lessless
I wonder if it’s possible to mimic a simple “class reopening”/inhertinace-based SEAM in Elixir to alter a module’s behaviour without edit...
New
New
sergio
Laravel just announced their Series A round for $57 million. If Laravel wasn’t already the defacto PHP stack, it now most certainly is. T...
New

Other popular topics Top

pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
AstonJ
You’re a programmer, so you don’t need spoon feeding with the conventional drivel about “this is an integer.” No. You need to know what’s...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
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
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 27727 240
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
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New

We're in Beta

About us Mission Statement