weakty

Wow, I haven't written anything about programming in a little while! Well, time to change that with a little post about Elixir meta-programming. I’ve been working away at a new feature for the Bike Brigade’s dispatch software. Today, I was about to write five handle_info callbacks in Elixir that did the exact same thing, when I wondered if I could do this with some meta-programming. Here’s the result:


  @impl Phoenix.LiveView
  for event <- [:task_created, :task_deleted, :task_updated, :campaign_rider_created, :campaign_rider_deleted] do
    def handle_info({unquote(event), entity}, socket) do
      if entity_in_campaigns?(socket, entity.campaign_id) do
        {:noreply, refetch_and_assign_data(socket)}
      else
        {:noreply, socket}
      end
    end
  end

Above, we loop through a list of symbols and define a handle_info callback, unquoting the event so that in the end, we end up with 5 unique handle_info matches.

That’s nice! But…people often warn of the dangers of using meta-programming. Without code comments, or if you’re not scanning closely, you might miss what this code is doing. You might miss a little bit of magic.

So while I’ve been writing this I remembered this would be better suited to using pattern matching with a when clause:


  @broadcasted_infos [:task_created, :task_deleted, :task_updated, :campaign_rider_created, :campaign_rider_deleted]
  def handle_info({event, entity}, socket) when event in @broadcasted_infos do
    if entity_in_campaigns?(socket, entity.campaign_id) do
      {:noreply, refetch_and_assign_data(socket)}
    else
      {:noreply, socket}
    end
  end

This is better not just because we’re avoiding meta-programming, but because everything we need to understand the code is right there — there are no N number of functions being generated behind the scenes and filling in our module via a for comprehension.

Thinking in pattern matching in Elixir takes a bit of time, but I’m slowly getting used to it.

Thanks for reading!