The Zen of Erlang (2016)
ferd.ca
ferd.ca
After a few years of Rust experience, it still pales in comparison to Erlang productivity for me.
I have wanted to learn Rust and Erlang, but I've wanted to learn Erlang longer. I know there are different reasons to learn either, but what makes you feel erlang makes you more productive?
There is very little boilerplate and very little in the way of irrelevant details.
I've spent a single day with Elixir and really liked it (if it was statically typed, I would have stuck with it), but I've only ever seen Erlang code (and stack traces), and honestly, the syntax looks really intimidating.
That said, Erlang has Dialyzer, which gives you 'optional' typing. Elixir can make use of it too, though I don't think it's quite as good (though I haven't used it in prod the same way). Basically, it'll walk through your code, infer types, and tell you anywhere the code can't work based on what it could infer. You can help it by adding type annotations as well. So for instance, you read from ETS; Dialyzer will infer it can be type "any". But, what's this, you append to it; it must be a list of some type then. So that place you're multiplying it by a number must be wrong, since you can't multiply a list by a number. But in reality what's coming out is a binary; both operations are wrong. Diyalyzer can't tell you that, but you can tell it that via type spec.
Regardless, I'd probably create new projects in Elixir at this point; mix is such a good tool, and Elixir has some real niceties (looking at you, actual string type and pipe operator), to where it would probably be my default at this point.
Far more Elixir developers I know have just given up on using Dialyzer altogether than the Erlang devs I know.
As for why elixir devs give up on dialyzer, I suspect that sometimes the messages can be cryptic because they are formatted as erlang terms. This is basically now a nonissue due to elixir_ls.
Eg: https://bravenewmethod.com/2011/02/22/socket-binary-data-str...
I don't know if any other language can do it this trivially.
match msg {
pattern1 => action1,
pattern2 => action2,
_ => {} // silently ignore
}It's based on PureScript, which has a great reputation, but adds all the benefits of Erlang.
> very carefully constructed set of trade offs
But also the VM has changed since 1980 (for example there are maps now) and the programming ecosystem has changed (we know what drives productivity in terms of how to effectively test, document, deploy, good documentation > separate header files), we also know more about things like how lexical metaprogramming is maybe not the best idea for IDEs or language servers, it's really tough to say that Erlang got everything right for time immemorial. And on some things Erlang hasn't moved yet (thankfully it seems like there's movement in documentation).
Elixir aimed for 100% Erlang compatibility.
It also provides minuscule overhead for each process so that creating a supervising process for every item isn't really a cost.
When you start talking distribution across nodes and hot loading code, that's where static typing starts to really bite you back because you don't have any way to enforce it across nodes or during a hot loading transition.
I agree, the status quo is that static typing often gives you more of a headache than profit. But I think that it actually could be the other way around, we just need to start thinking backwards-compatibility-first static typing, and it looks like an exciting area to explore.
https://github.com/purerl/purerl
Developers have perverse incentives, like endlessly refactoring the same codebase or architecting "scalable" and "abstract" solutions.
Video of the presentation: https://youtu.be/4ZIPijEqrNI
It is strong in the area because you have the perfect storm of large complex protocols bundled with the need for very high reliability and robustness of systems. Few languages does that particular mix as well as Erlang.
Edit: it's indeed controlled nodes and not code
[1] https://thenewstack.io/why-erlang-joe-armstrongs-legacy-of-f...
Some takes from one of the inventors of Erlang on Elixir https://joearms.github.io/published/2013-05-31-a-week-with-e...
tl;dr "It didn't take long, but pretty soon my gut feeling kicked in. This is good shit"
Everything is just thinking in terms of message passing between lightweight processes
Let me give you an example. I have an actor that asks for two objects from a DbActor, and then sends them to the AdderActor to get the sum. Without preemption, I have to do the following.
1. Send a message to get object A and object B. Return.
2. Wait for an object.
3. When I get the object, figure out if it is object A or B (or maybe it's something else entirely). Update internal state so that I know I need one more object. Return.
4. Wait for an object
5. Get the object, figure out if it is object A or B (or something else). Update internal state so I know that I have both objects. Send the two objects and my Add message to the AdderActor. Return.
6. Wait for the result.
7. Now that I've gotten the result, update internal state saying that I've completed my A+B operation. Either store the result of A+B or whatever.
This method requires a lot of internal booking and a lot of mutable hash tables in order to keep track of all the various stuff this actor is in the process of doing. If I'm trying to calculate A+B and C+D, I need to know how far along I am in each computation. This is a buggy and annoying process that creates a ton of complexity.
Let's look at how we could do it in Erlang:
1. Send a message saying we want object A.
2. Don't return, and instead block until we get A. Now we ask for B.
3. Block until we get B. Now send the A+B message.
4. Block until we get it. Do something. Return.
See how much easier this is? Because we can block, our code actually can be structured to look like normal, non-concurrent code. It can be executed in a sequential fashion, even though the actual computation is happening somewhere else. With Akka and Akka.net, we can't do that. We have to return as quickly as possible, or else we are going to lock up the entire system. This means that all of the implicit state that a normal program has (like current line being executed), must be stored explicitly by our program.
It sucks, but hopefully the JVM will get preemption sometime soon. The actor model doesn't really work with out it. And even though it doesn't work without it, it's still better than threads and mutexes.
https://getakka.net/articles/concepts/actor-systems.html#blo...
Coroutines in general are a form of cooperative multi-tasking (they must explicitly yield), but I might missing something about .NET's implementation.
> Examples are legacy RDBMS drivers or messaging APIs, and the underlying reason is typically that (network) I/O occurs under the covers
The issue with async/await is that APIs need to be extended with their async counterparts. If they don't, then you have to be sure not to invoke blocking calls. Java won't have this issue as the runtime will take care of preemption.
for {
a <- aProviderActor ? gimmeA
b <- bProviderActor ? gimmeB
aPlusB <- adderActor ? (add, a, b)
} yield aPlusBI've used Rails, Node.js and .NET before this, and none of them came close to Elixir in terms of developer productivity, not to mention system stability.
How much of this is due to (the minority of) devs that can code Erlang/Elixir being more experienced/productive regardless of the language? Or just having good tech management?
You're not going to see more or less Erlang anywhere, not even at Ericsson, due to Ericsson getting more or less business.
The software will be written regardless as long as there's some business and you're not going to notice outside Ericsson either way.
Besides, Huawei is free to use Erlang too. It stopped being Ericsson proprietary a long time ago.
2018 https://news.ycombinator.com/item?id=17100626
Discussed at the time: https://news.ycombinator.com/item?id=11058500
For example, I wondered if there is a GUI library for Erlang, and the response with the most votes here [1] is that people don't write GUIs in Erlang.
The other answers point to wrappers around libraries written in other languages.
I think that is suspicious for a language that has been around for such a long time now.
[1] https://stackoverflow.com/questions/97508/what-libraries-can...
https://www.youtube.com/watch?v=feAW1AVzNwo
But also there are GUIs (I believe there are wx bindings) that are shipped with erlang (wobserver for example)
By and large, though people are writing servers in erlang, so building GUIs has never been a priority, and by the time erlang got a kick in butt in popularity due to Elixir, the way to write a GUI in erlang, became "write a web interface in Elixir".
Finally don't necessarily trust stackoverflow; the entire elixir community has basically left SO and gone to elixir-specific fora, which we think is why elixir dropped off the SO developer's survey.
That's very surprising to me. Do SO's metrics of questions/answers/etc reflect this? If so, why the move? Was it organic? Organized?
I left because stackoverflow is not a community, I don't give a crap about the gamification, the incorrect answers most upvoted because they provide a quickfix rather than a proper fix, and I'd rather go in places where you can have an actual discussion when you need to re-frame problems since newcomers aren't generally used to the paradigms of the VM and OTP.
Stackoverflow felt like working for free just spending time answering things for imaginary points whereas other fora have more reciprocity available through richer dynamics that can help build communities.
Stackoverflow, to me, is a last resort more than anything else.
IMO that's what makes languages "great": domain specificity.
General purpose languages beg the scenario of a person who only knows 1 language and tries to do everything in that language instead of learning a more appropriate one.
1. It’s slow in number crunching, if you’re doing any computation it won’t be much faster than Ruby (and much slower than Python due to the scientific computing ecosystem) 2. The amount of libraries is negligible, many are abandoned, even on its home turf (networked applications). I.e. there is no maintained ssh server lib, whereas all popular languages have several. 3. To get the benefits of the platform, you need to deeply understand OTP. This is a serious learning curve. 4. Despite all the chest-beating about performance of Phoenix, it’s solidly mediocre on any benchmark (about on par with the fastest Python web frameworks). It’s okay, but nothing to write home about.
The problem with GUIs is that making a simple UI is relatively easy, but making a really world class native UI is practically almost impossible. Witness the fact that even Microsoft is using Electron instead of writing native GUI code.
One of the really fundamental problems is that GUIs need to be done in the native language of the OS (e.g. C++), so any scripting language either needs glue like pyqt or to talk over a socket to a GUI, which limits performance.
Having said that, you can make ok GUIs in Erlang with the wx libraries, and there is Scenic for making custom UIs for e.g. embedded systems https://github.com/boydm/scenic
The one place where it screws you over in erlang is the REPL, which I think is why Elixir chose to allow you to mutate the variable binding, (but the underlying values are still immutable). In my main code, I mark any variables that I will mutate binding (almost never) with a ! postfix sigil (idea stolen from Julia/Ruby)
http://blog.plataformatec.com.br/2016/01/comparing-elixir-an...
Source code control systems don't mutate in place. They create new versions.
All modern relational databases (Oracle, Sql Server, Postgres) don't modify records in place. They create new versions.
All cloud based file systems (google docs) create new versions.
When you have this mindset of 'any mutation needs to go into a different version, a new variable', it simplifies a whole lot of reasoning when things don't work as expected. Try it out.