christhekeele

christhekeele

Calling all Matchspecs!

:wave: Hey all!

I’ve been working on an elixir-to-matchspec compiler. Think ex2ms with support for a few more expressions, pattern support, tracing support, helpful errors, and some other niceties.

Right now it’s passing ex2ms’s test suite, and I’ve added many tests of my own, but… I know I’ve seen edge cases where bad matchspecs were generated during development that I forgot to jot down. Also, I’d love to see it build other matchspecs used in the field that people have crafted by hand!

So, it’d be incredibly helpful if anyone cared to share theirs to bolster my test suite! I’m interested in:

  • matchspecs passed to
    • :ets.select...
    • :recon_trace.calls/2
    • Registry.select/2
    • :dbg.tp...
    • :erlang.trace_pattern...
  • matchpatterns passed to
    • :ets.match...
    • Registry.match/4
  • especially anything with
    • non-trivial destructuring in the match heads
    • nested tuple literals in match bodies

All contributions greatly appreciated! :purple_heart:

Most Liked

mguilmineau

mguilmineau

A few samples from our code - hope it helps.

:ets.select( ets_name( customer ), [ { { { customer, :_ }, { true, :“$1”, :_, :“$2” } },
[ { :andalso,
{ :“==”, {:map_get, :a, {:map_get, :job, :“$2”}}, a},
{ :“==”, {:map_get, :b, {:map_get, :job, :“$2”}}, b}
} ],
[ [:“$1”, :“$2”] ] } ] )

:ets.select_delete( ets_name( customer ), ( for task_id ← task_ids,
do: { { { customer, :_ }, :“$1” }, [ { :“==”, {:map_get, :id, :“$1”}, task_id } ], [:true] } ) )

:ets.select( ets_name( customer ),
[ { { { customer, :_ }, { :, :“$1”, :, :“$2” } },
[ { :andalso,
{ :“>=”, :“$1”, Util.to_dets( date ) },
{ :“<”, :“$1”, Util.to_dets( Util.tomorrow ) }
} ],
[ :“$2” ] } ] )

:ets.select( ets_name( customer ),
[ { { { customer, :_ }, :“$1”, :“$2”, :, : },
[ { :or,
{ :“==”, {:map_get, :reattempt, :“$1”}, @auto },
{ :“==”, {:map_get, :reattempt, :“$1”}, @manual }
} ],
[ :“$1” ] },
{ { { customer, :_ }, :“$1”, @paused, :, : },
,
[ :“$1” ] },
{ { { customer, :_ }, :“$1”, @deleted, :, : },
,
[ :“$1” ] },
( if for_seeding,
do: { false, , [ true ] },
else: { { { customer, :_ }, :“$1”, :, :, true },
,
[ :“$1” ] } )
] )

christhekeele

christhekeele

I feel as if this is 50/50, personally.

  • Match specs are already an informal, loosely-documented sort-of-erlang-AST. They are difficult to debug and error prone.
    • The approach I am taking resolves this, as all specs are validated against erlang’s builtin ms test functions at compile time.
  • Traversing an even wider conceptual gap from sort-of-erlang-AST to Elixir just adds to the cognitive load in writing, debugging, and maintaining them.
    • The approach I’m taking passes all code through the Elixir compiler first, to throw all the familiar errors and warnings, before converting Elixir code into specs.

This is my real goal: not to solve these kinds of problems, but to make match specs more accessible, and therefore increase their adoption in general, so that more advanced tooling can be easily built on top of them without needing to understand the underlying syntax. What I’m working on was originally a proposal to the language itself, though I feel like it belongs outside it now.

Of course, targeting Elixir AST as the high-level format should help with this a lot: library authors can just leverage Elixir’s powerful macro system to translate things (ex: mnesia schemas, ecto schemas, ets queries) from Elixir code, to Elixir code. Then my library can handle all the fussy details of whether or not it’s a viable match spec without requiring further knowledge.

Not quite sure I understand here—are you saying that you have a known set of ids on hand you want to retrieve verbatim, and doing a single :ets.select/2 call with a match spec is not as efficient as a series of :ets.lookup/2 calls or a single :ets.match/2 call with a match pattern?

mguilmineau

mguilmineau

I support your effort and I hope I wasn’t giving a different impression. match specs are not intuitive, too different from elixir syntax and little discussed on the web. The pre-compilation validation is a welcome addition. The detailed match specs we currently have look unnecessarily intimidating. There is value in this effort.

My comment on full scan: we tend to duplicate values in :ets storage with keys designed to match the queries we run frequently, so as to use lookup or match instead of more complicated and slower select match specs. In other words, while we do use match specs they tend to be a temporary stop gap but eventually get simpler or are removed entirely, primarily for performance reasons.

Last Post!

christhekeele

christhekeele

Excellent, I love me some edge cases!

I didn’t know that! I’ll have to play around with this form to see if it is a potential optimization.

I think this is a case of holistic term ordering, a standard caveat of comparison operators on the BEAM. Sadly there’s not much my compiler can do to “correct” this, but I hope that by passing all MS code thru the Elixir compiler first it will benefit from the new typing warnings coming to comparisons. I need to play around with how those intersect…

That’s slick! I’m pretty sure my compiler supports emitting map literals straight out of an MS but definitely should make sure that’s in the test cases.

Where Next?

Popular in Discussions Top

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
CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -&gt; H; nth(N, [_|T]) when N &gt; 1 -&gt; nth(N - 1, T). Elixir Enum.at … coo...
New
Crowdhailer
I’ve been hearing much about the new formatter and it’s something I have been keen to try. I find examples buy far the most illuminating...
248 19814 150
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
chuck
Let me start by stating an assumption: Phoenix is a great approach to building REST APIs. There are many reasons for this, but I will ass...
New
tomekowal
Hey guys! I want to create a toy project that shows a chart of temperature over time and updates every 5 seconds. I feel LiveView is per...
New
crispinb
On reading dhh’s latest The One Person Framework it strikes me that Phoenix with LiveView is already pretty much this. However, never hav...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 131117 1222
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
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
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New

We're in Beta

About us Mission Statement