wktdev
In the following code I use agent to “save state” of a list and then I update the list.
(I know elixir does not have objects but naming my functions as such helps me reason about the code )
defmodule M do
def create_object() do
{:ok, pid} = Agent.start_link(fn -> [1, 2, 3] end)
pid
end
def update_object(pid, new_data) do
Agent.update(pid, fn (state) -> state ++ new_data end)
pid
end
def get_object(pid) do
IO.inspect Agent.get(pid, &(&1))
end
end
M.create_object() |> M.update_object([4, 5]) |> M.get_object()
The following code has the same result but does not use agent. What can the code that does use agent do that the following code can not? Asking this question is my attempt to see what I am not understanding.
defmodule M do
def create_object() do
obj = [1, 2, 3]
obj
end
def update_object(obj, new_data) do
obj = obj ++ new_data
obj
end
def get_object(obj) do
IO.inspect obj
obj
end
end
M.create_object() |> M.update_object([4, 5]) |> M.get_object()
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
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
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
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
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
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
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










Most Liked
hubertlepicki
The main difference is that Agent (or GenServer) runs in it’s own process.
This means that knowing the pid of Agent (or it’s registered name) you can retrieve/save state from different concurrent processes.
You can use Agent to say implement a dynamic configuration for the application. All HTTP requests are handled in their own processses, but they would be able to access this shared configuration. Then, you could update the configuration say from iex shell and it would be picked up by all other processes now on.
peerreynders
Hubert’s reply is correct
I’d like to explore some aspects in more depth and detail.
First of all many of us are still scratching our head in terms of finding valid use cases for Agents as evidenced by this topic:
Discussion about uses for Agent Processes
Hubert’s use case of changing the configuration state of a running system through the shell is a viable one - though I would imagine that sending a function to update the state is inherently more risky than simply replacing the old state with a new, known to be consistent, state.
Then there is the choice of your example - it is inherently sequential. I recommend that you watch:
Erlang Master Class 2: Video 1 - Turning sequential code into concurrent code
Your example forces a particular ordering on the sequence of operations which doesn’t take advantage of the capabilities of the Agent - there are no independent, concurrent parts in your computation.
Your use of an Agent can be roughly expressed as a
GenServerlike thisAgents are often used to introduce the concept of processes because the code looks initially much less arcane than
GenServercode. In your example the client code provides the function that is updating the Agent’s state. In myGenServerbased code I fixed the “meaning” of “update” in a module function to appendingnew_datato theGenServerstate.The point I’m trying to make is that
Agentcan be viewed as aGenServerturned-inside-out. With aGenServerthe functionality to change process state is fixed within the callback module - with anAgentthe computations (functionality) to change process state are provided from outside of the process.The whole point for an
Agent:or a
GenServeris that numerous (tens, hundreds, thousands, … of) other processes can concurrently append data to the list managed by process
pidwithout sharing state.In a typical conventional multi-threaded program that list would often be shared so that each thread could append its own data to the shared list - so the list would have to be explicitly protected by locks, mutexes, etc.
Now
Agent.updateandGenServer.callare synchronous calls - so they will block until the target process receives the message and sends a reply. For asynchronous processing there isAgent.castandGenServer.castNow when
update_object/2returns there is no guarantee that the list inpidhas been updated yet. But the code still works - becauseget_object/1is still synchronous and because here messages are processed in the order of arrival, i.e.{:update,new_data}before:get, the list will be updated before the state is returned.peerreynders
A lot can be learned by updating outdated code.
works even on http://elixirplayground.com/
GenServer version
Elixir playground doesn’t support
GenServer.stop.And finally the Agent version … it’s wrong in so many ways.
The following is more in keeping with how an Agent is actually supposed to be used - as a state container. As a result the chat is now peer-to-peer - there is no “server” as such. However the clients do not keep the “room” as part of their own state - that is farmed out to the agent and manipulated through the anonymous functions created by the various
handle_xfunctions.However it still remains a strange way of using an agent.
Last Post!
smpallen99
Some interesting points @peerreynders. To be honest, all my Elixir projects over the last 3 years have all been single node solutions. Busy ones, but all single node, mainly enterprise telephony relates. I have played around with multi node, but nothing commercially. With that said, I have not given much thought to the distribution aspect of Agents.
Also, when I design a module with an Agent, I typically add the api to the module. So the consumers are calling an API with data. In only one instance did I expose an interface where the consumer passes their own
fn. And I wasn’t very comfortable with the design.I am, however, staring to see the pain points around using Agents, especially for the inexperienced. Its been an informative discussion for me.
As for Agent vs GenServer, I guess I save a few lines of code. Basically its 1 function / API call for Agent vs 2 for GenServer. And not even that if I used something like
exactorwhich I’ve pretty well abandoned these days.I’m almost convinced to abandon Agents in favour of GenServers