Tony Pitale
Tony Pitale

Reputation: 1202

Store binary pattern match in a variable

I have a function that matches against some binary value:

  def parse(<<timestamp::binary-size(4)>>) do
    IO.inspect timestamp
  end

Unfortunately, my real "pattern" is MUCH longer than this. Would it be possible to store that pattern and match on it later?

@pattern <<timestamp::binary-size(4)>>
def parse(@pattern) do
  IO.inspect timestamp
end

Obviously, this doesn't work as I've written. And, no matter what I do with quote and unquote I can't seem to get this to work.

Upvotes: 3

Views: 574

Answers (1)

Dogbert
Dogbert

Reputation: 222448

You cannot store the pattern in a variable, but you can create a macro:

defmodule A do
  defmacro pattern do
    quote do
      <<var!(timestamp)::binary-size(4)>>
    end
  end

  def parse(pattern()) do
    IO.inspect timestamp
  end
end

A.parse("abcd")
A.parse("abcde")

Output:

"abcd"
** (FunctionClauseError) no function clause matching in A.parse/1
    a.exs:8: A.parse("abcde")
    (elixir) lib/code.ex:370: Code.require_file/2

Note that I had to use var!(timestamp) in the pattern. This is to disable Elixir's Macro Hygiene feature so that you can access that variable with the same name in the caller. You'll have to add var!() around each variable name in the pattern.

Edit: You can store a quoted pattern in a module attribute and then unquote it in the function argument:

defmodule A do
  @pattern quote do: <<var!(timestamp)::binary-size(4)>>
  def parse(unquote(@pattern)) do
    IO.inspect timestamp
  end
end

The output is identical to the macro code above.

Upvotes: 3

Related Questions