Aduril
Hello there,
Whenever I setup a new project, there is a small function I always add: reply/1. What does it do?
In a LiveView mount, handle_event or handle_info
instead of writing
{:ok, stream(socket, :posts, Blog.list_posts())}
or
{:noreply, stream_insert(socket, :posts, post)}
one should be able to write
socket
|> stream(:posts, Blog.list_posts())
|> reply(:ok)
or
socket
|> stream_insert(:posts, post)
|> reply(:noreply)
Therefore, a function called reply/1 could be added into Phoenix. It could be implemented somewhat like that:
def reply(socket, reply) when is_atom(reply), do: {reply, socket}
This could increase the readability (it’s faster to “scan” the code of your LiveView).
You can put that little function in your project, but I would suggest to make it a part of LiveView itself.
I am eager to hear your opinion on that ![]()
Trending in Proposals: Ideas
We are seeing a lot of warning logs like this:
navigate event to "https://someurl" failed because you are redirecting across live_sessio...
New
Other Trending Topics
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself.
My main conc...
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
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Most Liked- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
LostKobrakai
It’s not true that this is without value.
Those tagged tuples exist, because they do distinguish multiple distinct multi value return types.
:noreplyis not the only tag you’re able to return from those functions. E.g. forhandle_eventmay return{:noreply, Phoenix.LiveView.Socket.t()} | {:reply, map(), Phoenix.LiveView.Socket.t()}.And even for the callbacks, which cannot currently allow multiple distinct tagged tuples that’s what allows them to evolve without breaking changes to eventually in the future have additional return tuples. E.g.
handle_eventdidn’t always have the:replytuple as a valid return type. It was eventually added once the integration with js hooks became a thing. That would’ve been a more complicated change if you would’ve been allowed to just returnstatewithout tagged tuple before.Also this approach doesn’t really exist in isolation as well. The way those return values are structured are quite consistent between many different behaviours of various levels of abstraction backed by a process. You can look at
GenServer,:gen_statem,GenStage,Broadway,Phoenix.Channel,Phoenix.LiveViewand you’ll find that approach taken between all of them.So this actually is achiving what you’re calling for:
LostKobrakai
I think this is where the mismatch comes from. Indeed in the case of
{:noreply, state}or{:ok, state}it feels like you’re only transforming state. But there are in many places other options as well.mount/3can also return{:ok, state, keyword}handle_call/3can also return{:reply, term, state}handle_event/3can also return{:reply, map, state}Those callbacks are not just transformations of state, but transformations of state is just one of potentially many things they do and return information about. Sometimes those other things are even the only thing happening with no changes to state.
E.g. for me most simple callbacks look like this:
The state transformation is neatly contained in a pipeline, but the return of that state transformation is separate to the transformation itself. It doesn’t belong in the pipeline. This becomes apparent if the code changes and you need to return a reply:
:noreplyis literally telling the caller of the callback “there’s no reply to send for this one”. That’s not a state transformation.sodapopcan
This has been talked about before a few times. I used to have have separate
ok,noreply,reply,cont,haltfunctions but ultimately I found I preferred just using the plain ol’ bare tuples. I harp about “scannability” a lot and actually found this pattern to hinder it. With my eyes zooming through some code without actually reading any of it, I found it basically impossible to catch nested returns without a{poking out at me as the pipe version just looks like any other ol’ pipeline.I don’t think this pattern is particularly bad for those who like it, but I don’t think it belongs in LiveView as it’s really easy for anyone to implement themselves. Some people also do this which doesn’t require any extra functions:
Also, you will want to to change it to
reply/3mountis also allow to return a 3-tuple!Last Post!
sodapopcan
That monad thing is neat, though I personally don’t actually care that Elixir doesn’t have codified monads and kind of like that it doesn’t. Elixir hits this really nice mix of elegant and scrappy for me that not only makes it productive but also less gatekeep-y.