5 ms·
> In Erlang, the mantra is “abstraction is had by introducing another process”. This is probably "not a good idea", as processes introduce bottlenecks. Really
by throwawaymaths 3y ago
> In Erlang, the mantra is “abstraction is had by introducing another process”.
This is probably "not a good idea", as processes introduce bottlenecks. Really, if you want to abstract in erlang, you should, in 95% of cases really just write a behaviour.
Of course if you need to abstract over something stateful, yes, please write a process. The benefit being that you can do some pretty painless dependency injection (or at a minor readability cost compile time pick between modules) and inject the state in your tests.
- zilti 3y agoI really have to finally take a look at Erlang, it's been on my list for years
- fredrikholm 3y agoFor me, no language has been more fascinating as unlike most languages Erlang is very focused on distributed systems as a first class citizen and sells that, rather than the more common sales pitch of being exactly like other languages but with subjectively better syntax/semantics.
- xutopia 3y agoIf you prefer a more fun syntax I would consider Elixir instead of Erlang. It's transpired to Erlang so you get the whole ecosystem's benefits. One of my favorite features of Elixir is the |> operator. I find myself desiring it in all other languages.
- bmitc 3y agoTo be specific, Elixir isn't transpiled to Erlang the language. It's compiled to the Erlang Abstract Format. https://elixirforum.com/t/getting-each-stage-of-elixirs-compilation-all-the-way-to-the-beam-bytecode/1873/8 https://elixirforum.com/t/getting-each-stage-of-elixirs-comp... https://www.erlang.org/doc/apps/erts/absform https://www.erlang.org/doc/apps/erts/absform
- freedomben 3y ago(In Elixir) I've most recently found myself lamenting the indirection of processes as a ton of third party dependencies spin off processes to manage their state, and when something goes wrong (usually some argument I'm incorrectly passing in to a function call or something) the stack trace I get doesn't lead back to my code so I have to try and figure out the closest point to where I'm invoking it. Probably still a good tradeoff for immutability and the actor model, but an unfortunate downside that has pained me.
- throwawaymaths 3y agoI haven't found most 3rd party dependencies doing that unless they're making, for example, a request pool. Should we be shaming those libraries?
- freedomben 3y agoMaybe so, although there's usually at least some justification for it, whether it's performance related or just as simple as "the API can get a lot better when it can track some state so you don't have to pass every initialization value in every time." I particularly don't agree with the latter most of the time, but I can see how they arrive at the gen server conclusion.
- dqv 3y agoWhat libraries? You might be able to do something with the process dict depending on how the libraries are set up. Basically you create a process id that you use to track what's going on: @type trace_id :: nonempty_binary() @spec put_trace_id(trace_id()) :: term() | nil def put_trace_id(id), do: Process.put({:my_app_name, :trace_id}, id) @spec get_trace_id :: trace_id() | nil def get_trace_id, do: Process.get({:my_app_name, :trace_id}) @spec make_trace_id :: trace_id() def make_trace_id, do: Base.hex_encode32(:crypto.strong_rand_bytes(16), padding: false) It does require that, along the call path, you set that trace id whenever a new process is started. It gives you some visibility into what's going on, especially if you also do something like Logger.metadata(trace_id: get_trace_id()) after you call put_trace_id/1 That said, I think any library that does start processes like that should have some mechanism that lets us identify the provenance of the crash. "Crashed when trying to fribulate. Trace id xxxxxx"