Question

Is it a bad practice to pattern match against record as tuples in Erlang (or Elixir)?

Sample code: Assume we have defined this module:

defmodule Ween do
  defrecord TimeSpot, at: nil, tag: nil

  def proper?({ _, _, "home"} = v),   do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?(other),                 do: { false,  "failed with:     #{inspect other}" }

  def sample, do: TimeSpot.new(tag: "home")
end

If we define a test as follow:

defmodule WeenTest do
  use ExUnit.Case
  require Ween

  test "records are tuples" do
    case Ween.proper?(Ween.sample) do 
      { true, v }       ->  IO.puts v
                            assert(true)
      { false, v }      ->  IO.puts v
                            assert(false)
    end
  end
end

It will succeed.

Edit 1: @parroty The reason that here pattern matching against tuples tested is to simulate some "sort of" duck typing for records; the ultimate thing I wished for, should look like this:

defmodule Ween do
  defrecord TimeSpot, at: nil, tag: nil

  def proper?([tag: "home"] = v),          do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?([tag: "1234"] = v),          do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?(other),                      do: { false,  "failed with:     #{inspect other}" }

  def sample, do: TimeSpot.new(tag: "home")
end

So every record with a 'tag' field baring a "home" value would match the first clause. Of-course it seems there would be some performance penalties there.

Was it helpful?

Solution

Cesarini and Thompson say in their book Erlang Programming to never rely on the fact that records are implemented as tuples, since that implementation could change. See the accepted answer to this question.

OTHER TIPS

I think the record can be directly used for pattern matching (this would be better than using tuple structure).

defmodule Ween do
  defrecord TimeSpot, at: nil, tag: nil

  def proper?(TimeSpot[tag: "home"] = v),  do: { true,   "succeeded with:  #{inspect v}"     }
  def proper?(other),                      do: { false,  "failed with:     #{inspect other}" }

  def sample, do: TimeSpot.new(tag: "home")
end

Just for completeness (as this question is still very high on the Elixir tagged questions list): as of Elixir 0.13, records are deprecated (other than for interacting with Erlang code) and the question is now best implemented using Structs. These also conveniently give you the polymorphism that you desire (Structs are a form of Map)

http://elixir-lang.org/getting_started/15.html
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top