Crowdhailer
The Gen* behaviours in Elixir (and erlang) provide a pure interface.
One of the benefits of this is business logic is easy to test. No need to start processes just pass the arguments you want to test to handle_call for example and assert on one of the results.
I’m sure I read in a book that a pure interface was an important part of the setup, unfortunately I can’t remember which one so if anyone can point me to that again I’d be grateful.
Unfortunately with GenServer implemented as it is several things can’t be done in a pure fashion. For example sending a reply to a call in response to a later message.
It’s a fairly contrived example but I don’t believe this can be implemented in a pure manner.
defmodule PairUp do
use GenServer
def handle_call({:pair, pid}, from, :none) do
{:noreply, {:waiting, pid, from}}
end
def handle_call({:pair, pid2}, from2, {:waiting, pid1, from1}) do
GenServer.reply(from1, {:other, pid2})
{:reply, {:other, pid1}, :none}
end
end
I was thinking with some small changes to the GenServer design purity could be regained.
defmodule PairUp do
use AltServer
def handle_call({:pair, pid}, from, :none) do
{[], {:waiting, pid, from}}
end
def handle_call({:pair, pid2}, from2, {:waiting, pid1, from1}) do
messages = [
{from2, {:other, pid1}},
{from1, {:other, pid2}},
]
{messages, :none}
end
end
The key changes to this interface is that :send/:nosend are replaced by a list of {target, message} pairings, an empty list giving a same behaviour as no send.
I think the structure {[{target, message], state} could be treated as a writer monad. This might even be a helpful model to add type safety to message sending.
This post is really just me musing. my questions are?
- Is this a great idea or a horrible idea
- Does something similar exist already
Trending in Discussions
Other Trending Topics
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
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










Showing Posts 20 to 11- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
Crowdhailer
Not yet but I would very much like too.
mjadczak
It may be the case that the reply never comes if, e.g. the GenServer is (logically) waiting for some other call or cast before it decides to reply to the original caller.
roehst
Oh i’ll take a look at it. Did you ever try Elm? It is pretty nice to play with
Crowdhailer
So I have though about this quite a lot.
Finally having http as pure instructions where what led me to develop raxx. To model it like this you need a data structure for the request/response but that is a little of the core topic.
I think all the above points can be address with the following signature
for example.
Re dialyzer.
Because more than one spec can be added to a function I think you could specify a lot of information about the protocol
This says that the handle function does NOT handle the message
:m1when in state:s2Addresses
I think addresses could be the same as you can use for genservers i.e.
pid | atom | {:via, module, term}comms
I have run some very basic experiments in this project. feel free to ignore, i didn’t get very far but would like to revisit the project one day GitHub - CrowdHailer/comms: Explicit message passing for improved reasoning about actor systems · GitHub
roehst
I stumbled across this a few times while writing Elixir code. I separated the code into processes that return actions, and processes that execute actions… I did not go further because it was a application that integrated GitHub and Slack and what really broke purity was HTTP calls. And writing a framework for doing it went well beyond the scope of the project.
That said I think Elm has a great approach to managing effects purely and could be a good inspiration
I would love to collaborate on something similar for the backend
Now from a theoretical perspective, recursive types offer a basis for purely functional processes, that might be a solid starting point for more academic work, so I thought it is worth mentioning.
Roughly, a process is a function that takes a message and returns a reply and a new process (which is again a function that takes a message and … all the way down):
Does anyone know if dyalizer can check this kind of types?
voughtdq
Couldn’t you use an arbitrary
{to, tag}?i.e.
Crowdhailer
This quote is pretty close to saying GenServer is valuable because of the ability to test by just calling one of the handle_calls and checking the return values. (Not true in every case, e.g. GenServer.reply/2)
Crowdhailer
Yep that is the kind of thing im looking for
OvermindDL1
Hah nice! That’s new!
mjadczak
So it is!
And it turns out someone has done some work on formally modelling and verifying BEAM message passing already.