fceruti
I just wanted to share with you a small macro that has cleaned up many many lines of code for me.
Basically in my contexts I had this kind of code everywhere
|> Repo.transaction()
|> case do
{:ok, %{goal: goal}} = result ->
PubSub.broadcast_goal_created(user, goal)
result
error ->
error
end
A possible solution would be to add maybe functions
|> Repo.transaction()
|> maybe_broadcast_goal_created(user)
..
def maybe_broadcast_goal_created({:ok, %{goal: goal}} = result, user) do
PubSub.broadcast_goal_created(user, goal)
result
end
def maybe_broadcast_goal_created(result, user), do: result
Which is not ideal since I’d have to create one pair for each function in context.
Macros to the rescue!
Inspired by how IO.inspect prints and keeps moving, I created case_continue, which runs case, ignores it’s result and continues the pipe as if it was never there.
defmodule Timetask.Helpers.Macros do
defmacro case_continue(prev, do: block) do
quote do
case unquote(prev) do
unquote(block ++ [{:->, [], [[{:_, [], nil}], nil]}])
end
unquote(prev)
end
end
end
Now I can write it like this.
|> Repo.transaction()
|> case_continue do
{:ok, %{goal: goal}} -> PubSub.broadcast_goal_created(user, goal)
end
Much nicer huh? What do you think? Do you like the name? I also had in mind case_bridge or case_skip.
Trending in Discussions
The obligatory hello world thread!
Who are you and where are you from? :stuck_out_tongue:
New
Hey there,
It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
Hey folks,
I wanted to share with you a project I’ve been working on for a while: It’s an Open Source (AGPLv3) newsletter tool. Think Ma...
New
Hi everyone :waving_hand:
I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
In my third year of college, around 2010, I found Erlang. A few years later, I found Elixir. I liked the ideas at once: many small proces...
New
I’ve been tinkering with Lynx (by José) via hold_ledger. I used AI to write the code, a separate specification, the tests, and the Lean p...
New
Hi everyone,
I have 8 years of production experience with Erlang/OTP and I’m just starting to get to know Elixir. What would you learn f...
New
Other Trending Topics
Hey there,
I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first.
...
New
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly)
AI dream has many faces, but general...
New
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #code-sync
- #discussion
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #elixirconf-us
- #full-time-contract
- #podcasts-by-brainlid
- #blog-post
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #elixirconf-eu
- #processes
- #security
- #api
- #forms
- #performance










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
RudManusachi
Piping into
(see don’t pipe into case statements)
caselately became a subject for debatesMacros are awesome! ..mostly for stuff I do on my own
Especially adding up to the language syntax meant to be commonly used across the project might not be obvious to the team who work with the code.
_https://elixir-lang.org/getting-started/meta/macros.html#foreword_
Whenever I notice
caseof just two branches one of which just returns the input - I think ofwithWith your macro we can handle more than just one happy path, though.
al2o3cr
I don’t find the
error ->boilerplate that annoying, personally. I always prefer to unpack results (both successand error) from passingEcto.MultitoRepo.transactionas close to the transaction as possible, because otherwise operation names become an accidental part of the function’s interface.I’m also not sure how the above macro accomplishes the task - it seems like a result other than
{:ok, %{goal: _}}will fail to match in the generatedcasestatement.fceruti
Interesting, is this like a tab vs spaces kinda thing? hehe
I’ll check it out.
Yup, bug found! Too quick to publish (solved above)
Good point. You could still unpack the result in a later
case doto give shape to errors.or even
To me it feels natural to have a separate step in the pipeline dedicated to call external services. But that’s just me. It’s definitely clearer when dealing with
Repo’supdate,insertordelete, where Ecto’s interface is usually the function’s interface →{:ok, struct}&{:error, Changeset}.RudManusachi
It depends. Sometimes if “call to external service” fails we would want to rollback the transaction =)) can’t come up with a reasonable example from top of my head why would we took a transaction before external service call, but I have a feeling that I faced that in the past.
derek-zhou
Using the
then/2macro introduced in elixir 1.12, you can do:Sebb
Where is the debate? This just says: dont do it!
IloSophiep
Am i missing something or would one possible solution to define something like
Maybe.mapthat “hides” thatcaseexpression away in a generic way (or insteadResult.mapdepending on your context, but that’s not really important)?MaybeandResultmodules are common in lots of languages nowadays, so i hope it’s clear what i mean with that. That way you don’t have to define a helper for every situation.RudManusachi
Sorry, should have mentioned. Some discussions can be found here and there.. for example in threads in twitter like this one. Or in some threads in comments in HackerNews [1][2]
Sebb
There is no case for not piping into case in the links you provided.
fceruti
Great observation about “maybe” as a name. I actually renamed the macro to
maybe_case.I fail to grasp what you are trying to argue thou. Could you provide some high level code?