`tap/2` runs side effects in pipelines

almirsarajcic

almirsarajcic

yesterday

0 comments

Need to log, send a message, or cache a value mid-pipeline without breaking the flow? tap/2 executes a function for its side effect, ignores the return value, and passes the original input through unchanged.

order
|> calculate_total()
|> tap(&Logger.info("Order total: #{inspect(&1)}"))
|> tap(&send(self(), {:order_ready, &1}))
|> format_receipt()

Functions like Logger.info/1 return :ok and send/2 returns a pid—neither returns your data. Piping directly to them breaks the chain. tap/2 lets you run these side effects while keeping your data flowing.

Common use cases

# Notify processes mid-pipeline
user
|> Accounts.update_profile(attrs)
|> tap(fn
  {:ok, user} -> send(self(), {:profile_updated, user.id})
  {:error, _} -> send(self(), :profile_update_failed)
end)
|> handle_result()

# Cache intermediate results
expensive_computation()
|> tap(&Cachex.put(:my_cache, "result", &1))
|> further_processing()

# Log at specific pipeline stages
request
|> parse_params()
|> tap(&Logger.info("Parsed: #{inspect(&1)}"))
|> validate()
|> tap(&Logger.info("Validated: #{inspect(&1)}"))
|> execute()

Any function you want to call for its side effect—not its return value—belongs in tap/2.

Comments (0)

Sign in with GitHub to join the discussion