Hacker News new | past | comments | ask | show | jobs | submit login
The Zen of Erlang (2016) (ferd.ca)
192 points by swyx on July 19, 2020 | hide | past | favorite | 79 comments



I’ve seen ex python or node.js developers say they are just as productive in Rust.

After a few years of Rust experience, it still pales in comparison to Erlang productivity for me.


I'm really looking forward for Hamler lang to become mature and popular https://github.com/hamler-lang/hamler

It's based on PureScript, which has a great reputation, but adds all the benefits of Erlang.


Running on the Erlang VM and all the benefits of Erlang aren’t the same thing. Erlang itself is based on a very carefully constructed set of trade offs. You don’t add something without giving up something else.


As long as you give an escape hatch to access the Erlang VM, the rest is somewhat superficial. I am way more productive in Elixir than I am in Erlang, but that's probably because of the way my brain is wired.

> 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).


True, I’m mainly talking about stronger types. It’s something people have asked for a lot and generally the trade offs aren’t taken into account.

Elixir aimed for 100% Erlang compatibility.


Sorry, I mostly meant the VM/platform, not the Erlang language. I assume it'll give all the great features like process trees (with dependencies), introspection, logging, discoverability and other tools that make it great for distributed programming.


The language itself brings most of that. The biggest thing that the BEAM provides is a preemptive scheduler to ensure that you can run millions of concurrent processes without any one of them dominating the CPU resources, ensuring consistent performance regardless of load.

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.


> 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.



Nice! I don't know Erlang world very well, but the person I know (N2O author) for some reason puts his money on Hamler and says that the author is known for successful projects including https://github.com/emqx/emqx Other than that – whoever wins :)


I've been on the fence in learning erlang. I use python mostly and the industry around me uses Java or maybe golang.

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?


I think Erlang's pattern matching alone is a strong point for Erlang. Makes a generic server-client protocol parsing very trivial to implement.

Eg: https://bravenewmethod.com/2011/02/22/socket-binary-data-str...

I don't know if any other language can do it this trivially.


Rust can also pattern match the same, if I recall correctly.


Yeah but what happens in rust if your match doesn't match the pattern? The compiler won't let you. In erlang, it throws an error, which you can let the runtime eat up. This can be a strategy for extremely lazy error handling.


I'm not sure what you mean. In Rust, you can write:

    match msg {
        pattern1 => action1,
        pattern2 => action2,
        _ => {}  // silently ignore
    }


I know about Erlang's let it fail philosophy but why would you want something to be caught at runtime when it could be caught at compile time? It doesn't seem to have any valid reasons.


Netsplits, for example. You don't want to keep track of every service that needs to be taken down with the dropped connection and notify them something bad has happened. Log, crash, cleanup the failure domain, restart, back off, reconnect later. Zero lines of code in erlang.


Erlang concepts of processes, list comprehensions, pattern matching and extremely simple file/socket interfaces just make problem solving a breeze.

There is very little boilerplate and very little in the way of irrelevant details.


Not sure if you've used Elixir, but if so, how would you say it compares to Erlang?

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.


The syntax is alien (coming as it does from Prolog, which few people know), but it actually is as much a feature as an anti-feature. You end up not bringing your own understandings to the language (as illustrated by the one instance where it seems familiar - if statements do not behave the way you expect them to; it pattern matches and must match to true in one of its branches or it's a runtime error). It also doesn't have macros, so far less 'magic' in the libraries and things. Either way, the size of the language to grok is smaller than Elixir, so I'd argue in some ways it's easier, even if it's offputting.

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.


Elixir is arguably better with dialyzer than erlang, for various reasons, like the way that structs work.


In practice it is much worse because Elixir's structs boil down to maps with a special key, and the analysis in Dialyzer can get confused there because it works them with Erlang's map semantics rather than Elixir's.

Far more Elixir developers I know have just given up on using Dialyzer altogether than the Erlang devs I know.


Maybe I'm mistaken, but in my experience dialyzer has caught several typing errors I've made in structs, which I have gone on to successfully fix.

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.


Asking developers if they're "productive" is absolutely the wrong metric. Developers, well, love writing code. Lots of code. But in reality, code is a liability, not an asset. (That Bill Gates quote about airplanes and weight, etc.)


I'm sure developers are not measuring their own productivity in lines of code. Rather how fast tasks get completed or how easy it is to modify code etc


I wasn't talking about lines of code.

Developers have perverse incentives, like endlessly refactoring the same codebase or architecting "scalable" and "abstract" solutions.


This is a loose transcript of presentation given at ConnectDev'16.

Video of the presentation: https://youtu.be/4ZIPijEqrNI


Is Erlang about to be the next big thing due to companies unable to use Huawei and instead going with Ericsson for 5G deployment?


The Erlang ecosystem (including my personal favorite BEAM language, Elixir) has been kind of a secret weapon for a lot of companies for years. There are a handful of freelancers in the community who have had the experience of going to work for a company doing Erlang/Elixir, only to be told they can never reveal the company’s identity because they consider the language a competitive advantage. One big corp went so far as to say they use Java in all their public-facing info (including hiring).


I'll just come out and say that this is true for us at PriceTable. :)

I'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 actually has to do with using the language? Unless the companies are solving very specific technical problems that Erlang/Elixir are designed to solve, what really matters is productive software devs and managers, and that is more defined by expertise and domain knowledge in a particular language than the language itself (within reason: you're not going to choose C over Ruby for a web app backend).

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?


I've heard this before, and despite my cautiously being on the Elixir bandwagon, this story triggers my BS sensor. Assuming their competitors are already invested in another language, it will be expensive for them to switch, and the company using Erlang/Elixir gets good press from using a hipster language. Can someone point to specific people that said they were barred from revealing their BEAM-using employer?



Does it though? StackOverflow's predecessor was created one year after this was written, meaning it was likely written in an environment without SO. Easily finding the solution to your every problem is the ultimate programming language feature.


What does Erlang offer that the JVM or .NET don't?


While there is actor support through Akka and Akka.net on the JVM and .NET, neither of them support preemption like the BEAM does. Preemption of blocking actors is a game-changer in terms of how you write and structure concurrent code. I wrote a BitTorrent client in Scala using Akka and found myself desperately wishing that I could write actors in a blocking style. The amount of extra complexity and book-keeping required to write purely non-blocking actors is truly staggering.

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.


In Scala/Akka, you could use the ask operator and compose the resulting Futures, something like this:

  for {
    a <- aProviderActor ? gimmeA
    b <- bProviderActor ? gimmeB
    aPlusB <- adderActor ? (add, a, b)
  } yield aPlusB


Yeah, but you're blocking the thread. It's very very easy for you to deadlock the entire system writing code like this.


As you point out, the JVM is getting preemption by means of Loom. .NET already has coroutines (async/await) so it should already do what you stated.


I'm not super familiar with .NET, but if it supports preemption, they why this?

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.


It is specific to blocking APIs, as per the page:

> 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.


The concept of failure domains is baked into the runtime, and not an afterthought.


Check out the OP.


Its already the biggest thing ever, but nobody knows it. 90% of the Internet nodes is controlled by erlang code [1]

Edit: it's indeed controlled nodes and not code

[1] https://thenewstack.io/why-erlang-joe-armstrongs-legacy-of-f...


If you use "passes through" as a standard, surely C would be the biggest thing ever since Linux+BSD+Windows make up way more than 99% of operating systems and those are all written in C.


Ha yes fair point! I mainly wanted to indicate that it's used more than people think. It's the backbone of telecom


Erlang: Cobol/Telecom: Banks/Internet: Money


Windows has also a good part of C++ and we all know Microsoft's stance on keeping C compilers around.


C is definitely bigger than people assume.


It’s not exactly what the quote says - 90% of the traffic goes through nodes _controlled by Erlang_. See:

https://news.ycombinator.com/item?id=17218190


Thanks for pointing that out, I've updated my original statement


Arguably, it already is all over the place in telecommunication. But indeed, Huawei being somewhat limited could push more people to buy Ericsson equipment, where a large part of it uses Erlang.

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.


I've spent two years with them and didn't see Erlang anywhere. It was occasionally mentioned as obscure thing you are forced to do in some other department, while rest considered themselves lucky to be using C++. There were also teams doing Java, Python, JS, Matlab, roughly in that order of popularity.


My latest project is in Elixir after going through Rust and Python as candidates. Erlang / Elixir isn't the best candidate for _everything_, but I will be using it in the future for just about everything I can because of how much I like it.


I highly suggest looking at Elixir. It makes things much better in my opinion.

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"


Elixir is the only language that really blew my mind in its capabilities while still using a readable and fairly easy syntax.

Everything is just thinking in terms of message passing between lightweight processes


I don't see why it would matter.

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.


I don't think ericsson really uses erlang that much internally.


They do. It’s part of control planes for their next 5G stacks.



I have the feeling that Erlang is great, but only if you are working in a very specific problem domain.

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...


The "specific problem domain" for Erlang is scalable, reliable network services.

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


check this out:

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.


> the entire elixir community has basically left SO and gone to elixir-specific fora

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 was active on the Erlang stackoverflow.

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.


I have pretty thoroughly searched the internet and Erlang/Elixir seems suspiciously devoid of any real downsides. I see small community, not as many tutorials, package ecosystem not as developed being mentioned a lot, which implies that if there were more Erlang programmers it would be a perfect language. The only downside that seems real is performance issues in computationally intensive use cases, and I'm not even sure what that applies to.


The downsides are:

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.


For point 2, there is a maintained SSH server lib in the standard library. Its default options execute Erlang shell commands, but can be configured to run other stuff (https://erlang.org/doc/man/ssh_server_channel.html).


your first statement is correct. if you can leverage none of the language's strength, why do X thing in it? what can be gained?

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.


I watched the presentation some months ago on YouTube. Really really well done. Thanks to that video I was able to get some tricky concepts of Erlang that I was previously struggling with.


The incessant functional evangelizing everywhere I go reminds me of why people don't like vegans


Immutable variables are too weird for me.


If you are willing to get over it, you'll find that huge classes of errors disappear. It's a very nice feature that lets you cut a bunch of bs, clarify your code, and make everything much more comprehensible. When you can mutate your values, you have to read any given block of code with a ton of suspicion (and possibly trace through control flow, keeping branches in your head, god I don't miss doing that). If your values are immutable, you don't have to do that.

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)


Yeah but it's a critical piece of how Erlang and its BEAM VM are able to deliver on their concurrency and fault-tolerance guarantees. Turns out that allowing variable values to change randomly throughout the system is really bad for building correct concurrent systems.


The runtime takes care of making immutability fast (enough), you realise how good it is when debugging code that does lots of mutations via references in other languages. Also it helps to reason about parallel code because nothing is being mutated from another thread.


I'm not for sure exactly what you mean by immutable variables, but if you are referring to Erlang not being able to rebind variables, then you might check out Elixir, which does have variable rebinding. All data in Erlang and Elixir is immutable but the rebinding of variables is handled differently between the two.

http://blog.plataformatec.com.br/2016/01/comparing-elixir-an...


Immutability is very very common. It makes reasoning much simpler.

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.


I agree it's weird, but you get used to it and now I'll occasionaly write code without reassigning to variables in 'normal' languages... I still miss for loops though.


I legitimately don't see why you even need mutation like, 95% of the time. Like what are you doing such that a variable, itself, needs to change?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: