nahiyan
Let’s say I want to put a flash message, a session item, and redirect the user. Here’s my code:
conn
|> put_flash(:info, "Login successful!")
|> put_session(:current_user_id, user.id)
|> redirect(to: Routes.page_path(conn, :index))
All 3 of these functions just toss around the “conn” variable, modifying it in the process.
Now, if I change the order of the function, such as like this:
conn
|> put_session(:current_user_id, user.id)
|> redirect(to: Routes.page_path(conn, :index))
|> put_flash(:info, "Login successful!")
The flash message gets lost along the way. Why does it make a difference? Aren’t we just defining the action through the “conn” variable?
Trending in Questions
Hello!
Suppose you are building workflow (order / task / payment) processing system with the following requirements:
Each workflow con...
New
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app?
Looking for hints regarding:
Addi...
New
Kia ora,
We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
Hi all, I wanted to ask how the community is dealing with post-release steps.
Today we have Ecto migrations, which make sure that the db...
New
Hello,
I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New
Other Trending Topics
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 10- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
peerreynders
Welcome to the forum!
By the time
Phoenix.Controller.redirect/2returns the 302 HTTP response has already been sent.https://github.com/phoenixframework/phoenix/blob/v1.4.10/lib/phoenix/controller.ex#L392-L400
So modifying the
connstructure afterwards will have no effect on the response.You can’t saddle the horse when it has already bolted out of the barn.
nahiyan
Thank you so much for your response; really appreciated! Coming from a Haskell world, I’m so used to Monads and pure functions.
kelvinst
I can’t see why do you think that because of that kind of behavior that function is not pure (not even sure if that’s what you think too). I mean, the pipe operatore (
|>) does get theleftargument and send as the first parameter on therightfunction, so callingput_flashright in the beggining and calling in the end will call it with 2 different params, since in the latterput_sessionandredirectwould return a new, altered,Plug.Conn.peerreynders
Haskell (and Elm) is singleminded in its pursuit of purity. Functions like
put_sessionandredirectcould exist but rather than directly (and rather imperatively) interacting with the HOW (horrible outside world) those functions would simply register the intent to interact with the HOW somewhere inside theconn. It’s only when the completedconnis handed over to the runtime that those interactions with the HOW happen under the runtime’s full control.The Clojure community often talks about how immutability helps them to push side effects to the edge of the system. This effect is captured architecturally in the Ports and Adapters architecture (see Functional architecture is Ports and Adapters by Mark Seemann).
The way
put_sessionandredirectin Phoenix work aren’t consistent with a functional core imperative shell kind of approach and could be surprising to somebody coming from a background of functional design which practices a higher level of purity.kelvinst
Well, I still cannot see the functions there interacting with the HOW in any other way than actually receiving the params, and if that is what you mean by interacting with the HOW, well it must be really tedious to do anything in Haskell. But well, I don’t know much of it, so maybe I should invest a bit on learning it before asking those questions.
Yeah, I know about that, I was just really not getting the specific case there. I mean, I know BIFs, NIFs and processes can introduce side effects, but how
put_sessionandredirectdo that? This specific part of the code in isolation is pure as far as I can tell: they receive the params, and return the result, if the same params were given again and again to the same function, they would still get the same result over and over. Where is the side effect? Where the HOW gets in the game for that case?peerreynders
It would be tedious to do something like that in Erlang/Elixir.
Given how Haskell embraces monads (less intrusively in Elm) it is actually relatively simple but it does require a significant shift in thinking. “Regular” programming is like flying the plane yourself - programming in Haskell is more like filing a flight plan and having the autopilot do all the dirty work.
put_sessionstores information in session storage which depending on configuration is eitherPlug.Session.ETSorPlug.Session.COOKIE. Putting a value into an ETS table is interacting with an external mutable entity and therefore classifies as a side effect.redirectsends the response. To do that it has to interact with the web server which is part of the HOW. And sending the response is a side effect.Update: looking at the code
put_sessionsimply updates theconnstruct - so the interaction with the session store is actually happening at the edges (via thepluginstantiation).It’s the
callto the session plug that fetches the state from the session store and places it in theconn. At the same timebefore_sendis registered to save the session state back to the store just before the response is sent.https://github.com/elixir-plug/plug/blob/v1.8.3/lib/plug/session.ex#L60-L104
kelvinst
Right, in that case I agree, but the default is the cookie, and in that case the side effect is pushed to the edge of the system, when the response is sent.
Alright, true, yeah, there are side effects, was assuming that function worked on a different way (by doing something like leaving the response to be sent in the end of the plug pipeline). You are totally right, sorry for all the confusion, if the response was not sent on the
redirect, there would actually be no reason to block people from setting the flash after calling it. Thanks for all the talk and sorry to take your time to explain that while I could figure it out by myself just digging a little on Plug’s and Phoenix’s code.OvermindDL1
Think of the BEAM as a big Algebraic Effect engine in Haskell. The only ‘mutation’ goes through algebraic effects that the BEAM calls message passing. Everything within a process is entirely immutable, including the message passing, but it’s the ‘effect’ of passing messages between processes that causes the mutation in the overall world. The BEAM is pretty easy to reason about as a haskeller when thought of like that (because that’s what it really is).
nahiyan
I was about to write all these to you, but peerreynders wrote it much better than I could. Let me explain why I was confused. The main issue here is that most of the functions take the
Plug.Connstruct as an input and generates a new (slightly different) version of it as an output; there was no side-effect, not even in theput_sessionfunction. However, theredirectfunction was different. It had side effects - that is, sending the response to the user through the server. I was too blind to side-effects, assumed that a functional language would at least try to avoid it until the very edge. I thought the side-effects would be declared through thePlug.Connstruct, but only invoked after it is returned.Should have checked the docs before I started this thread, but it’s nice to see people discuss about this and explain the situation to me. Really liked Elixir and Phoenix’s community, you guys are great!
OvermindDL1
Not how functional algebraic effect systems work, the ‘effects’ happen immediately and the structures stay fully immutably functional.
With algebraic effect type systems you can even get fake mutation-looking variables that are still entirely immutable. ^.^