
My favorite Erlang Program (2013) - Tomte
http://joearms.github.io/2013/11/21/My-favorite-erlang-program.html
======
lostcolony
What I found interesting (or very, very boring, depending on how you think
about it) about this when I first saw it is that this ability is just due to
the nature of how receive works. That is, you can receive any kind of message,
at any time. Want to listen to a different set of messages? Just call a
different receive clause, be that in a different function, or inline.

I remember having a coworker who was in love with Akka. He was trying to sell
everyone on it, despite my team's having a strong Erlang presence. He showed
us Akka's "become", talking about how powerful that could be, and how Erlang
didn't have anything comparable. He didn't seem to realize that Akka's needing
a special keyword for it was actually a limitation rather than a feature, that
Erlang didn't have a special keyword to allow you to do it because it didn't
-need- a special keyword to allow you to do it. That's not a dig at Akka, or
Scala (it's an impressive language in its own right), but rather to point out
how sometimes we miss the complex capabilities a simple set of abstractions
can give us.

~~~
_asummers
Re: Akka, to paraphrase James Gosling's comments on Java "We brought a bunch
of Java programmers halfway to Erlang".

~~~
phyrex
FYI that wasn't Gosling, that was Guy Steele:
[http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/m...](http://people.csail.mit.edu/gregs/ll1-discuss-archive-
html/msg04045.html)

~~~
_asummers
My mistake! And in retrospect, Guy Steele saying that makes way more sense.

------
_asummers
We've been experimenting with Elixir at work, and it's been really cool to
drop down into the Erlang ecosystem and see how people think when they're
designing OTP programs, especially when it comes to things like Riak and
Mnesia and those sorts of things. My only complaints about this ecosystem is
that everything feels scattered in specific places (I've had to read a lot of
books, versus being able to read tutorials) and that it's very hard to tell an
abandoned project from a feature complete project on GitHub. You can generally
look at downloads in the Hex package manager for a rough idea of popularity,
but then again build servers can inflate unpopular packages. Someone in the
Elixir slack joked to me "75 stars? That's super popular for Erlang!". I can
deal with it, but I wish it weren't so.

All that said, I think I'm going to stick around with these languages.
Everything feels very well designed and battle ready, in stark contrast to
using JS. Elixir also seems to remove a lot of the cruft and awkward syntax of
Erlang, and having Lisp-style macros makes the GenServer boilerplate go away
entirely.

~~~
qaq
Elixir did make Beam/OTP more accessible and more "fun" :)

~~~
9919839219
Fun is in the eye of the beholder. I'm worried that Elixir will take off
because it's "hip" and ruin the chances for other people to use a pure and
consistent language (Erlang) at work.

It is amazing what kind of middleware bloat is forced unto people these days.

~~~
sotojuan
One could argue that Erlang/OTP has had decades to be used at work, and no one
wanted to (sadly). Elixir taking over doesn't affect Erlang because Erlang
wouldn't had become more popular over time anyway.

~~~
vegabook
I personally am doing BEAM now mainly because of Elixir. It's undeniable that
a "hip", and let's face it, young, crowd, having chosen Erlang/BEAM, gives it
a big breath of fresh air (this is NOT to insult the experienced Erlang devs -
it's just a fact that a new young crowd choosing your tech is an endorsement).
Interestingly though, I'm more and more intrigued by the underlying
technology. Personally I am not a fan of some of Elixir's design choices f.()
versus f() for example, and maybe, just maybe, I'll do Erlang now.

Overall though, it was a total blast the other day to just run 10 000
processes so easily, within milliseconds, and watch all my cores go to max
without messing with threads or even the (somewhat obtuse) Go channels. Actors
really are easy to reason about. I like this model so much that I'm even
looking at it for C (C++ Actor Framework).

~~~
infinite8s
I'd be interested to hear about your experience with the C++ Actor Framework.
It seems like without the larger ecosystem of Erlang/BEAM for fault tolerance
CAF is just a nice coroutine library.

------
nemoniac
"It is no exaggeration to regard this as the most fundamental idea in
programming: The evaluator, which determines the meaning of expressions in a
programming language, is just another program." \-- Abelson & Sussman, SICP.

------
tombert
What I find amusing about this is that raw receives are actually kind of
frowned upon in the Erlang community, but the creator is still using them, and
the language is still kind of beautiful and cool.

This isn't in any way to talk negative about Joe Armstrong or Erlang, but more
to show how cool the language is: even non-idiomatic code scales and is
wonderful.

~~~
lostcolony
Slightly tangential, but, I think it's more not using gen* in a supervisor
hierarchy is frowned upon. Using raw receives within ~that~ sometimes is the
right solution.

For instance, I had an instance where I needed to serialize requests out to an
external piece of hardware. Various user or system events would determine
hardware control events that needed to be sent out, and then responses needed
to be listened for to determine if they were successful or not, and return
that error the user. Essentially an asynchronous, but serial, process. I had a
gen_server to synchronize access to the hardware.

Now, the way I implemented this was, with each call that came into the
gen_server, I'd send a message via gen_tcp, and then listen for the response
as a raw receive inside of the same call. The alternative, to stay in the
gen_* structure, would have been to send and finish, and then handle the
response in the handle_info (since gen_* is coming back as a raw message). But
that would have allowed more sends to occur in between the initial send and
getting a response back, which would break the serialization we needed to
ensure, and would have lost the reference to who had sent the initial request
(since I was reusing the socket, and the acknowledgements from the hardware
didn't include any sort of session), making it impossible for me to respond
properly to the original caller.

So with a raw receive in there, it effectively became like a 'become' server,
in that at the top it was a gen_server that implemented a gen_tcp "send"
server, and then after sending it temporarily took on the characteristics of a
gen_tcp "listen" server via a raw request (though obviously it was listening
on the socket even before sending), before reverting back to the "send" server
that waited for the next thing to send.

In fact, as I recall, while we were serializing our sends, there were certain
types of events being broadcast by the hardware that we needed to drop even in
the raw receive, so it was recursive. That is, our send server became a listen
server, and stayed as a listen server until either we got the response we
wanted, or a timeout was hit, at which point we'd revert back to the send
server.

~~~
sigmaml
This is exactly how we are using a raw `receive` in one of our production
systems -- multiple asynchronous, but serial within, processes.

Thanks for sharing this. It gives me more confidence in what we have done!

------
mietek
How would this program look like translated to Haskell?

~~~
tome
id

(I'm about two-thirds joking)

