| Comparing "features" side-by-side is a naive, "consumer-mindset" approach. Instead one should try to understand design-decisions and how they fit together - the subtleties. Devil is in the details. For example, having an receive expression and pattern-matching and simple typing (like everything is a term - self-evaluating or an expression or a list of terms) makes your code shorter, self-evident, easy testable. Now let's look one level down. Pattern-matching on binary data (alternative to costly parsing) is so quick that in OTP they do matching on TCP packets in real-time. Conversion from terms to binary and back is also quick. So the the "central idiom" - message-passing - is just sending and receiving a list of terms (atoms) on a language-level (guarded pattern-matching, like on function arguments) while messages will be encoded into efficient binary form and delivered by Erlang's runtime. Again, almost everything in Erlang fits together pretty well because it is layered system founded on proper principles and design decisions. Immutable data, share-nothing process isolation, light-weight processes, common and simple data-representation format based on simple types, pattern-matching on everything, etc. It is almost like industry-strength Lisp system - a few layers of DSLs, using which one describes the real-world abstractions on different levels on different sub-languages (based on special forms and function composition). gen_server is the most common example of such kind of "vertical" decomposition. You have to write only "pattern-matching on receive", while lower layers of abstraction (encoding, protocols) and upper levels (process supervision) are clearly separated with proper abstraction barriers. Of course, it is possible to code something like this in Java, but there are the subtleties. GC for mutable data could not be as efficient as one for immutable data. No mutable state, no sharing, no locking, no problem. These aren't just slogans. So, Erlang is a small language designed around proper concepts. It "wins" not only in terms of lines of code, but in efficiency, resource usage (Erlang runs on 16Mb RAM). I could go on, but I hope the idea is already clear. It is not a "list of features" what matters, but which ones we have and especially don't have, and how they are fit together. In small mostly-functional languages like Lisps or Erlang or ML-family they fit perfectly. http://www.erlang.org/doc/man/gen_server.html |
I imagine you are referring to the full stack, as JVM and CLR implementations do exist which require a few hundred KB.
As for the rest I fully agree.