Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I write it fully acknowledging that programming language flamewars are pointless, but this article just shows that you don't even have to try hard to create a biased comparison.

Here's the essential difference between Go and Erlang: Go gets most of the things right, Erlang gets way too much wrong.

So what does Go gets right but Erlang doesn't:

* Go is fast. Erlang isn't

* Go has a non-surprising, mainstream syntax. You can pick it up in hours. Erlang - not so much.

* Go has a great, consistent, modern, bug-free standard library. Erlang - not so much.

* Go is good at strings. Erlang - not so much.

* Go has the obvious data structures: structs and hash tables. Erlang - no.

* Go is a general purpose language. Erlang was designed for a specific notion of fault tolerance - one that isn't actually needed or useful for 90% of the software but every program has to pay the costs

* Go has shared memory. Yes, that's a feature. It allows things to go fast. Purity of not sharing state between threads sounds good in theory until you need concurrency and get bitten by the cost of awkwardness of having to copy values between concurrent processes

So sure, if you ignore all the major faults of Erlang (http://damienkatz.net/2008/03/what_sucks_abou.html, http://www.unlimitednovelty.com/2011/07/trouble-with-erlang-..., http://ferd.ca/an-open-letter-to-the-erlang-beginner-or-onlo..., http://sacharya.com/tag/erlang-sucks/) it compares very favorably to Go.

You just have to overlook ugly syntax, lack of string type, lack of structs, lack of hash tables, slow execution time. Other than those fundamental things, Erlang is great.



> but this article just shows that you don't even have to try hard to create a biased comparison.

So, let's see you detailed unbiased analysis...

> * Go is fast. Erlang isn't.

Hmm. Given that you accused the author of making biased comparisons, I would expect some more detailed information there. "Faster" doing what? Assembly is faster, Go isn't. Ok, let's use assembly then.

> * Go has a non-surprising, mainstream syntax. You can pick it up in hours. Erlang - not so much.

I think Erlang syntax is small and self consistent. If ; and . are the biggest stumbling blocks to learning a new system. Ok, maybe Erlang is not for you.

> Go is good at strings. Erlang - not so much

Erlang is very good at binaries. It can even do pattern matching on them. Decoding an IPv4 packet is 2 or 3 lines of code only.

> Go has the obvious data structures: structs and hash tables. Erlang - no.

Erlang has obvious data structures -- maps, lists and tuples?

> * Go has shared memory. Yes, that's a feature. It allows things to go fast. Purity of not sharing state between threads sounds good in theory until you need concurrency

Quite the opposite. You can get easy concurrency if you don't share thing between concurrency contexts. You also get low latency response and non-blocking behavior.

Erlang shares binary objects above a certain size behind the scenes as well so those don't get copied during message passing.

It also has Mnesia, a built-in distributed database. It is used heavily by WhatsApp to share data between primary and back-up instances of processes running on different machines.

> You just have to overlook ugly syntax, lack of string type, lack of structs, lack of hash tables, slow execution time. Other than those fundamental things, Erlang is great.

Ok it looks like we only have to overlook syntax. Sound good to me then, I can handle . instead of ; and I will also learn and use Go because both are very cool and interesting tools.


> Assembly is faster, Go isn't. Ok, let's use assembly then.

That's pretty flawed logic. It can be used to dismiss any valid statement. "B is better than A at property C." "Z is better than B at property C; let's ignore the valid A vs B comparison."

What matters is how much better something is at a given property, how valuable that property is (to you/your tasks), and what the cost that improvement is - in the context of the big picture.

I like and use Go not because of any single aspect, but because I enjoy the entire package. It has some good parts and some weak parts (e.g., I wish the `go build import/path` command would be consistent in generating/not generating output in cwd regardless whether the target package is a command or library - that way it could be reliably used to test if a package builds without potentially generating files in cwd).


> That's pretty flawed logic.

Exactly. I was replying to his message and mocking his way of conduction a conversation. That should be viewed with that in mind.

> "B is better than A at property C." "Z is better than B at property C; let's ignore the valid A vs B comparison."

Yes. I think you probably want to direct that at gp post, not my post ;-) You also probably want to use different capitalization for properties than to entities (or at least letters from the other end of the alphabet), like say B is better than A at property x

> I like and use Go not because of any single aspect, but because I enjoy the entire package

Yeah Go is great I like it too!


Yes, it is flawed logic, but you were using so I don't see why you should object to it. And his goal was to show that.


>That's pretty flawed logic.

To show that it was "flawed logic" was the whole purpose of his remark.


> Hmm. Given that you accused the author of making biased comparisons, I would expect some more detailed information there. "Faster" doing what? Assembly is faster, Go isn't. Ok, let's use assembly then.

This makes big difference. With pure Go I can do computation heavy things, for example - I've implement some information retrieval methods in Go (indexes, stemmers, ranking and so on). I can't do the same in Erlang, because my map based inverted index, written in Erlang will be to inefficient. I can write it in C, but in my case - most of the application complexity is located in this information retrieval part. Because of that, efficiency is a big deal for me.


> You can get easy concurrency if you don't share thing between concurrency contexts.

We typically don't call that concurrency. Some resource has to be under contention, otherwise its just plain-old parallelism. In Erlang, you have to ship everything to everyone, but the resources are still technically shared...just very inefficiently.


I say you do.

Concurrency is a property of algorithm. Parallelism is a property of the running environment. The hope is given that you have large amount of concurrency, that concurrency would be reasonably and easily distributed over parallel execution units (CPU, sockets+select loops, goroutines, tasks, processes, separate machines, VMs etc...).

So if you have concurrency in your problem domain/algorithm ( say web page requests for example ), and, your language has reasonable ways to handle it. Abstractions like processes, tasks, etc, you can make each request spawn an isolated, lightweight Erlang process (it takes just microseconds and only a few Ks of memory). Then finally at runtime, if you have a multi-core machine or started your Erlang VM with a good number of async IO threads, there is a good chance that you'll get good parallelism too! But if you only run that bytecode on a single core machine, you might not get parallelism but concurrency will still be there.

> Some resource has to be under contention,

Why? That is just resource contention. You don't want resource contention if you can avoid it. Think of concurrent as independent units of executions.

> In Erlang, you have to ship everything to everyone, but the resources are still technically shared...just very inefficiently.

Because it keeps things (including faults, but also logical decomposition) simple. Also it maps well to real life. You have to send messages to other people, emails, phone, image. You don't directly plug a shared network back-plane into their brain. So when that crashes the whole group dies. You want to send a message to them and then continue minding your own business.


Concurrency is a property of systems in which several computations are executing simultaneously, and potentially interacting with each other (stolen from wiki). Here simultaneous could mean interleaved (multi-threading on a single core) or at the same time, but the interacting with each other part is key. They have to communicate, they have to communicate what they know about the world, what they know can change...they necessarily share state whether explicit or not.

Parallelism is is actually doing stuff at the same time, usually for a performance benefit, in which case, you aren't going to be using any of these slow FP languages anyways (but there is always Java + MapReduce, which is kind of functional). Your Erlang code will run "faster" relative to single core Erlang code, but if you honestly believe that you are being parallel fast...

> Because it keeps things (including faults, but also logical decomposition) simple. Also it maps well to real life. You have to send messages to other people, emails, phone, image. You don't directly plug a shared network back-plane into their brain. So when that crashes the whole group dies. You want to send a message to them and then continue minding your own business.

I get it: back in the old days before cell phones and screen sharing, we'd have to use carrier pigeons to send messages to each other, so we just sent messages out and minded our own business. But somewhere down the line, we gained the ability to interact in real time via language, looking at and modifying the same stuff even (I think this happened 50,000 years ago or so). We've never been able to recover from these impure interactions.


Parallelism is is actually doing stuff at the same time, usually for a performance benefit, in which case, you aren't going to be using any of these slow FP languages anyways (but there is always Java + MapReduce, which is kind of functional). Your Erlang code will run "faster" relative to single core Erlang code, but if you honestly believe that you are being parallel fast...

Erlang's shared nothing architecture is wonderful for avoiding cache misses. (False Sharing) That's a big stumbling block for good parallelism on today's multicore machines. Also, each process having it's own GC helps even more, and GC is an even bigger problem. Go also makes less use of GC than other langs.


You are aware that Erlang was invented to route telephone calls, which maps very well to message passing concurrency? Erlang is after all not a pure functional programming language.


> and potentially interacting with each other (stolen from wiki). [...] but the interacting with each other part is key.

Sorry don't see it. It seems you took something that was optional and turned into "key". It is not key. potentially means they can interact but they don't have to.

It seems you conveniently misinterpreted the definition from wikipedia to fit your idea of what concurrency and parallelism is.


Erlang does not specify how the message passing semantics is achieved, in principle it could be implemented with shared memory. But then it is hard to garbage collect processes independently, take Haskell as an example. It uses shared memory concurrency (STM) and the garbage collector thread has to stop the world to collect. Message passing also allows to transparently distribute the system over several nodes.


Note that the people who espouse Erlang are espousing the Erlang VM (mainly because it doesn't have a name besides "the Erlang VM".) Nobody likes Erlang's syntax. Nobody likes Java on the JVM either, but Clojure's pretty great. Use Elixir, and you get pretty syntax, and also "string support" and "a consistent stdlib" for free.

And, since other people have already rebutted your statements about structs and hashes, I'll ignore that. †

On needing speed: for IO-bound operations (concurrent ones especially), Erlang is faster than Go. For CPU-bound operations, Erlang knows it can't beat native code--so, instead of trying to run at native-code speeds itself, Erlang just provides facilities for presenting natively-compiled code-modules as Erlang functions (NIFs), or for presenting native processes as Erlang processes (port drivers, C nodes.) If you run the Erlang VM on a machine with good IO performance, and get it to spawn the CPU-bound functions/processes/C-nodes on a separate machine with good CPU performance, you get the best of both worlds.

And finally, on "every program having to pay the costs": is someone forcing you to use Erlang to create something other than fault-tolerant systems? Learn Erlang. Learn Go. Learn a bunch of other programming languages, too. Use the right tool for the job. The article is the rebuttal to people who claim that Go replaces Erlang in Erlang's niche, not a suggestion to use Erlang outside of its niche.

---

† For a bonus, though, since nobody seems to have brought this point up: Erlang has always had mutable hash tables, even before R17's maps. Each process has exactly one--the "process dictionary." It's discouraged to use them in regular code, because, by sticking things in the process dictionary, you're basically creating the moral equivalent of thread-local global variables. However, if you dedicate a gen_server process to just manipulating its own process dictionary in response to messages, you get a "hash table server" in exactly the same way ETS tables are a "binary tree server."


Erlang's syntax is not my favorite, but as a professional programmer, it's just something you deal with. You get used to it, and in the end it's ok to work with. Over time, as a programmer, unless you live in some kind of Java silo, you are going to deal with lots of different languages and syntaxes. I've used, professionally: C, Tcl, Perl, Python, PHP, Java, Ruby, Erlang, SQL, HTML, and probably a few other things I'm forgetting. After a while, you get to the point where you can pick something up and use it and appreciate what's good about it without getting hung up on its warts, unless they are such that they really prevent you from being productive. Erlang's syntax does not fall in that category.


> Note that the people who espouse Erlang are espousing the Erlang VM (mainly because it doesn't have a name besides "the Erlang VM".) Nobody likes Erlang's syntax.

I think lots of people like Erlang's syntax and find it well adapted to what Erlang strives to do. There are certainly people who don't, but like its features, but I don't think its at all true that praise for Erlang is just praise for BEAM (and, yes, the current Erlang VM does have a name, as does its predecessor, JAM).

I mean, Erlang's supporters have made Erlang-to-C and Erlang-to-Scheme compilers, and the main distribution includes a native code compiler (HiPE), so its pretty clear that its supporters don't think that the VM is the only good thing about Erlang.


Author here, I like Erlang's syntax :)


I like the erlang syntax, and think its pretty easy to reason about honestly.

The only thing thats goofy is the ,;. endings but I just stopped thinking about them after a few months of writting erlang and it became second nature just like everything else.


do you think that BEAM is just the name of the current implementation of the Erlang virtual machine?

can somebody reimplement a BEAM in the same way you can implement another JVM?


strmpnk beat me by 7 minutes, here's a link to the Erjang project: https://github.com/trifork/erjang

It's not really "BEAM on the JVM", it's actually a translator of BEAM compiled code to JVM bytecode. But the concept is similar, the target for Erlang is important, but so far a variety of things have been used. JAM was the original VM, later BEAM, later BEAM with HiPE. See [1] for some more information. There was also, apparently, an Erlang-to-Scheme translator. It'd be interesting (does this exist yet?) to see someone implement Erlang semantics in Racket.

[1] http://www.erlang.org/faq/implementations.html


While it's true that Erjang translates BEAM code, BEAM itself also does this to yet another more modern internal code (. I'd still consider both BEAM implementations.


Yes, though Erlang has many built-in functions that make it more than just a byte code runtime. See Erjang with the j for an example of a BEAM written on the JVM.


One thing that complicates the construction of a new compatible virtual machine is that the beam files are actually pre-processed at load time into another internal format that is then executed by the vm. Nevertheless see for example http://erlangonxen.org/ they have build a new vm running on top of xen.


> * Go has a great, consistent, modern, bug-free standard library. Erlang - not so much.

Erlang has one of the most battle-tested standard libraries around. OTP is rock solid. It may not be bug free (I don't know that any language can claim a bug free standard library), but it's damn close.

It's pretty obvious you haven't spent much time at all with Erlang based on your points here:

- Claiming "X is fast, Y isn't" is not even an argument, you should've just left that out.

- Arguments about syntax are rather pointless, but Erlang has very consistent syntax, and it's small. You can pick up Erlang in a couple of hours if you are familiar with FP concepts.

- I haven't encountered any real problems working with strings in Erlang. It may not have a bunch of standard library functions for manipulating them, but it's pretty trivial to do most things you would in any other language. It makes up for it with how much of a breeze it is to work with binary data.

- As mentioned previously, structs aren't datastructures, and Erlang has an equivalent (records) for those anyway. Erlang has trees, maps, tuples, lists - I would consider those a lot more obvious and necessary.

- Erlang and Go are both general purpose programming languages. They don't share the same design goals though. You could write a Go program to do a poor approximation of what Erlang is good at, and vice versa, the point though is to use the proper tool depending on the application. I don't know where you got the idea that fault tolerance isn't important for "90% of software", but the software I work on certainly requires it.

- Your argument about shared memory makes it clear you haven't actually used Erlang. The copying of values between processes is abstracted away from you entirely, there simply is no awkwardness. Perhaps there is in Go.

You are claiming the article is biased, but your post is riddled with it. There are certainly problems with Erlang, but none of the things you list are one of them (except perhaps strings).


To be fair, the standard libraries do have some unexpected inconsistencies. The array module indexing at 0, whereas everything else starts at 1, setelement being (index, record, value), but the similar feeling dict/orddict:store being (key, value, dict) (so the value and the collection items are switched between the two), things like that. Nothing really major, but a few things that mean you end up looking at the docs or autocomplete now and again because you forget argument ordering.

Erlang strings are quite inefficient if you aren't careful, and their printing is just terrible; a lot of the Erlang community uses binaries where possible instead, since those behave more like you would expect and are generally faster (especially since concatenation can be achieved with io_lists). It's a fair point; most people trying Erlang assume strings are a basic data type (since they were in whatever language they're coming from), they don't know to use binaries instead wherever possible, and so as soon as they see how slow they are, or when they get a non-printable character in it and the entire string prints as a list of integers, it's rather offputting.


The way I see it, arrays and binaries start a 0 because they represent an offset. Others start at 1 because they represent a position (first, second, third, ...) instead.

For the function and argument orders, there's no explanation for that one.

Erlang strings are a whole other subject, for which I recommend you give an eye to this blog post for the rationale behind a lot of their behavior: https://medium.com/functional-erlang/7588daad8f05 . It's a decent read on the topic.


Definitely good points. Your first is one of those really small, but also really annoying things about Erlang. I spend a lot more time with Elixir than Erlang, and while the first one is addressed, and the the second one is mostly covered, printing is still a pain point for people new to the language. Once you understand the caveats, it becomes a non-issue, but it's certainly frustrating for new users of both languages.


> Go has shared memory. Yes, that's a feature. It allows things to go fast. Purity of not sharing state between threads sounds good in theory until you need concurrency and get bitten by the cost of awkwardness of having to copy values between concurrent processes

There are approaches that allow the flexibility of shared state without the possibility of lurking data races or, worse (in Go's case) lack of memory safety. Even JavaScript has such a solution now (Transferable Objects). In fact, Erlang itself has one such approach: ETS.

To be honest, I don't think unrestricted shared state is the right thing in a programming language. It just invites too many bugs (and race detectors don't catch enough of them).


I don't know that much about Erlang, or Go for that matter, but there are a couple of things that seem to be at issue:

* From what I can tell the times I've looked at it, Erlang's syntax is pretty standard if you're used to functional programming. Sure, if your background is in C and Java, you might have a hard time picking up Erlang syntax, but if you have experience with Haskell or ML, it will be nothing new, except for (that I can tell) its syntax for bit-level operations.

* Structs are not data structures. They are a way to represent objects. Erlang has these as well, in the form of Records, which as far as I can tell are pretty much exactly the same thing as structs.

* Hash tables are only really useful with mutable data, which has its own set of issues and which Erlang does not have (much). Erlang does have maps, which act much the same way but are immutable.

I think it really comes down to that Erlang was designed for a restricted set of uses, which makes it really excel there but seems to hamper it in other areas.


> Hash tables are only really useful with mutable data

But maps (arbitrary k:v associative arrays) are not, they're useful in all sorts of contexts. And r17 adds EEP43 maps[0] to Erlang (though IIRC only with constant keys at this point)

[0] http://www.erlang.org/eeps/eep-0043.html




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

Search: