Why Make Erlang a Functional Language?

Why Does Erlang Have Weird Syntax?

I’ve heard the argument many times. People “don’t like Erlang’s syntax so [they] don’t like Erlang.” I, for instance, didn’t understand the block terminator syntax when I was first learning Erlang, so I asked Yariv Sadan about it:

Erlang syntax came from Prolog. The ‘end’ keyword is used to end code blocks that are contained inside the body of a function, and the ‘.’ symbol is used to close top-level function definitions.

Yariv Sadan

But what is the purpose of such a strange syntax? Is Erlang’s syntax really that weird or is it the single-assignment semantics which people don’t like? Erlang’s SAS derives from the functional programming paradigm which begs the real question: “Why is Erlang a functional language?”

The answer in a nutshell: To attain more language features, like message passing in Erlang’s case, the language incurs some overhead so efficiency gains must be made to compensate. It’s the same concept behind data structures: In order to know more about data, semantic restrictions can be imposed. In this case, the data is the program source itself and the imposed restriction is data immutability.

Erlang’s data immutability can be split into two levels: intra-process variable immutability and inter-process data isolation.

Why Doesn’t Erlang Have Share Data?

Concurrency is obviously the justification for Erlang’s isolation memory model, with the alternative being locking to synchronize destructive shared data operations. Lock complexity makes scaling hard because locks aren’t composable and are unassociated with the shared data. If data isolation is enforced between concurrent components (what Erlang calls processes), composibility can be maintained because destructive shared data modifications do not occur. Composability, or building instructions with instructions, is an inherent concept of programming and it’s why sequential programs are desirable.

This example excerpt from an older java.lang.StringBuffer class illustrates a common locking misconception. The author wanted to compose the length and getChars calls into one atomic operation to ensure critical data wouldn’t be modified between them. The author attempted to compose the calls by wrapping them in a synchronized method which locks this, not sb. Unfortunately, another thread could still modify sb in between the calls.

public final class StringBuffer {
  public synchronized StringBuffer append(StringBuffer sb) {
      int len = sb.length();
      ... // other threads may change sb.length(),
      ... // so len does not reflect the length of sb
      sb.getChars(0, len, value, count);
      ...
    }
    public synchronized int length() { ... }
    public synchronized void getChars(...) { ... }
    ...
}

Software transactions and message passing are fundamentally better synchronization abstractions than locks because of, among other things, composibility and accuracy, at the cost of greater overhead. STM can be built from message passing and I consider both to be acceptable replacements for lock based synchronization.

Why Does Erlang Have Data Immutability?

It seems that intra-process data isolation would be enough for a clean synchronization scheme, yet this is not entirely true. The immutable shared data model can be made even more complete when applied at the local sequential data level to achieve even more benefits:

  • Immutability efficiency gains compensate for message passing overhead.

    Immutability of data can, in many cases, lead to execution efficiency in allowing the compiler to make assumptions that are unsafe in an imperative language.

    Wikipedia

    To reiterate what I said earlier, the restriction of data immutability allows the compiler to know more about the program and as a result, regain some efficiency.

  • Immutability simplifies type policies for message passing.

    In Scala, [an OOP language with message passing,] you can send between actors pointers to mutable objects. This is the classic recipe for race conditions, and it leaves you just where you started: having to ensure synchronized access to shared memory.

    Yariv Sadan

    To expand on the type policy issue a bit more, it’s simpler to make all data immutable, both local and shared. This reduces the need for special cases intended to disallow sending pointers, or data structures containing pointers, through message passing. This congruency keeps message passing at the core of Erlang’s semantic focus.

  • Immutability makes Garbage Collection simpler, faster, and soft real-time.

    The generational [Erlang] collector is simpler than in some languages, because there’s no way to have an older generation pointing to data in a younger generation (remember, you can’t destructively modify a list or tuple in Erlang).

    James Hague

    Again, more restrictions means different ways of efficiency gains.

Downsides to Erlang’s Non-destructive Memory Model

Many common algorithms are designed with destructive memory in mind. As a result, Erlang doesn’t have some of the same types of data structures and libraries as imperative languages. This, combined with the confusion of learning a completely new programming paradigm, can be a large deterrent for learning functional languages. But what libraries Erlang lacks is largely made up for by an extensive actor based library platform.

Virtually all “big” Erlang libraries use Erlang’s features concurrency and fault tolerance. In the Erlang ecosystem, you can get web servers, database connection pools, XMPP servers, database servers, all of which use Erlang’s lightweight concurrency, fault tolerance, etc.
Yariv Sadan

Erlang is clearly a domain specific language, focusing on problems that can be solved with parallelism. Erlang’s libraries favor this same domain and Erlang holds its own against even C in the targeted many-thread/process arena. Note: the “thread-ring” test on the last line of the chart:

note the thread-ring test

An Erlang web server was also compared to Apache as another more practical comparison (again, intentionally a problem in Erlang’s domain). “Apache dies at about 4,000 parallel sessions. Yaws is still functioning at over 80,000 parallel connections.” So, Erlang may be hard to use because of its lack of conventional libraries or its different syntax, but as I’ve hopefully shown, the differences were chosen by design with good reason. Erlang is clearly one of the strongest languages in its parallelism domain and after a little over 20 years, is a very mature language.

    None Found
  • http://www.eflorenzano.com/ Eric Florenzano

    Also, I think that functional programming’s inherent referential transparency makes it much harder to screw up in the highly concurrent types of programs that Erlang was designed for.

  • https://www.humani.st Luke Hoersten

    Good point. That’s similar to what I was trying to get at with the “type policy issue” discussion but you’ve hit it right on I think. To me, at least, it makes Erlang a much more natural language to program in because it’s clear what “the Erlang way” of doing things is.

  • http://dynamictyping.org mattrepl

    Functional programming doesn’t require syntax as messy as Erlang’s [1] and Prolog, from which Erlang’s looks were taken, is a logic programming language.

    Also, Erlang’s ugliness in referencing functions as arguments [2] is pretty annoying for a FP language.
    __

    [1] See Haskell, ML family, or Clojure.

    [2] “fun someFn/<arity>” instead of “someFn”. A good example of coding for the compiler.

  • chris

    Please don’t post again until you know what “begs the question” actually means.

  • riggy

    Prolog is a “logical” programming model, not “functional”. The erlang syntax has nothing to do with the fact that its functional.

  • https://www.humani.st Luke Hoersten

    Your absolutely correct and actually that was the point I was trying to make. Though Erlang looks weird on the surface, it’s actually much more fundamentally different than people realize. It’s almost like complaining that a 5,000 page book’s cover is too hard to look at when there are 5,000 pages of content behind it. I never meant to imply that Prolog was a functional language. I was simply trying to get the “syntax issues” out of the way to get to the good stuff =)

  • https://www.humani.st Luke Hoersten

    Your absolutely correct and actually that was the point I was trying to make. Though Erlang looks weird on the surface, it’s actually much more fundamentally different than people realize. It’s almost like complaining that a 5,000 page book’s cover is too hard to look at when there are 5,000 pages of content behind it. I never meant to imply that Prolog was a functional language. I was simply trying to get the “syntax issues” out of the way to get to the good stuff =)

  • https://www.humani.st Luke Hoersten

    From Wikipedia:
    “In contemporary usage, ‘begging the question’ often refers to an argument where the premises are as questionable as the conclusion.”

    That’s exactly the usage I intended. It’s almost like complaining that a 5,000 page book’s cover is too hard to look at when there are 5,000 pages of content behind it. The syntax (the premises) are just as questionable as the conclusion.

  • https://www.humani.st Luke Hoersten

    When I say that “Erlang’s syntax derives from the functional programming paradigm,” I don’t mean to imply that Prolog is a functional language. I’m trying to point out that the syntax was chosen to try and facilitate the functional paradigm. Whether that was achieved or not is not in the scope of this post. The real point of this post is on data immutability and is why syntax was only mentioned in the first few paragraphs. I was trying to show that someone who wanted to bash on Erlang certainly could find something more fundamental than the syntax which they didn’t even create.

    I in fact agree that Erlang has a sub-par syntax but again, that wasn’t the point of this post.

  • daniel b. giffin

    yeah, the syntax for referring to top-level functions is pretty absurd. i’ve only barely peeked at Erlang, but i’m fairly sure the reason for this particular eccentricity is that (on account of the language’s roots in Prolog) lower-case symbols are “atoms” (while upper-case symbols are variable references).

    so when they added closures to the language (see Armstrong’s fascinating “History of Erlang”), these could naturally be assigned to (upper-case) variables and then referred to by same. but top-level functions, historically lower-cased and distinguishable from atoms only by the syntax of their use (function application versus argument-passing), had to have their names mangled (prefixed with “fun”, etc.) in order to distinguish them when used as arguments.

    (i don’t know why the compiler is so lazy as to require that you specify the function arity.)

    it seems the best solution would have been to leave Prolog behind and name functions in the same way as other variables, reserving a special naming convention for atoms. Common Lisp’s “:foo” syntax is not bad, and would leave lower-case names for variables.

    i’m also worried about the scope of Erlang’s atoms — instead of using them to distinguish record types, i would prefer abstract datatype constructors (ala ML or Haskell) that are assigned to variables and thus scoped like everything else so that software can be safely composable (are atoms universally scoped in Erlang?!) — but maybe this is an important mechanism for making hot code-update feasible (i’ve used a similar mechanism to ease schema migration in persistent object databases).

  • Anderson Octavo

    it’s = it is
    its = possessive

  • rvirding

    I think that if you actually looked at Erlang you would see that the reason for this is very simple and obvious. In Erlang it is perfectly legal to have *different* functions with the same name but with different arities, so if you want to reference a function uniquely you need to specify the arity. Of course, in some limited situations this may not be necessary but in the general case it is.

    This is usually demonstrated in the second version of factorial shown, the tail-recursive one.

    Sorry for being so sarcastic here but this feature is so basic that to have missed it is really surprising.

  • http://concise-software.blogspot.com/ Alain O’Dea

    This is a very good overview of the reasoning behind some of the more fundamental design choices in the Erlang VM. I found it very interesting and informative.

    Why does Erlang copy data between functions and messages if it has immutable data? It seems like copying is only really required for isolation if data is mutable. I have read that it certain circumstances (large binaries or lists for example) that the arguments/messages use shared memory under the hood if the receiver is local.

  • https://www.humani.st Luke Hoersten

    Erlang may or may not actually copy the data. The point is that if the user is unable to treat the data as mutable, the compiler or VM can know more about the data and optimize where possible. Think of it like copy-on-write except without the write, we don’t ever need to copy. So to the user, the data is always “copied.” Similar tricks are done with tail recursion etc.

  • http://philharnish.tumblr.com Phil Harnish

    Is this the library you mentioned in our conversation? I am pretty familiar with these modules–I even used a couple in my final project (pg stands out). Unfortunately there is nothing in here that I saw could be forced into a priority queue.

    I seem to remember going through these modules with you to see if anything would work. It was so long ago so I may remember wrong :)

  • https://www.humani.st Luke Hoersten

    There is no direct implementation of a priority queue in the Erlang stdlibs as far as I know but it has everything you need to build one. It’s pretty reminiscent of C++’s stdlibs with sets, queues, trees, and dictionaries. Googling “erlang heap” turned up a heap sort which looks comparable to any imperative language. You wanted something pre-made though, correct?

  • Greg M

    Nice article, the core point is very sound, but a couple of minor flaws: Firstly the syntax of Erlang comes largely from Prolog as you said, but Prolog is not a functional language (and one might argue that putting so much syntax from a logic-programming language into a functional language is a big part of what people are complaining about with Erlang syntax). And secondly I don’t believe that too much work has gone into using the immutability properties of Erlang code as a basis for compile-time optimization, although in theory it’s certainly possible. Unfortunately Erlang only has the nice properties of functional languages at the smallest scale, the explicit fine-grained concurrency makes it harder to reason about on a larger scale.

  • https://www.humani.st Luke Hoersten

    I agree with you on both points. The first one I’ve addressed countless times already in response to other comments.

    The second point, I believe, is partly why Erlang has been so popular in industry: it’s a small and simple language. Simple fine-grained explicit concurrency works well and composes well enough with a very shallow learning curve. This was done by focusing on a smaller problem set and cutting some of the functional features available in academic languages. Implicit concurrency, for instance, is still very academic and doesn’t have the pragmatic efficiencies that I tried to highlight in the conclusion of my post. There are already many fully-featured functional languages out there and you see how well they’ve done in industry. Point taken, though.

    Most functional languages start with abstraction and cut away until the hardware level is reached. Imperative languages tend to start with hardware and add abstraction. Erlang is one of the few functional languages that took the lessons of the highly abstracted functional languages and made it machine aware. Hybrids are the key and are why languages like Python and Ruby are becoming so popular.

  • Pingback: Martin Owen Has A Blog : Erlang Talk - Why Functional Programming?

  • Banador

    Your site has beautiful layout and it's readable. Thank's also for information!

    Too bad Erlang sucks in the shootout. It gives some wrong signals about the language to newbies.

  • https://www.humani.st Luke Hoersten

    Thanks for the comment. Unfortunately, I know what you mean. Programmers seem to be conditioned to look for a catch-all language and languages that fit a specific domain are easily cast aside for the wrong reasons.

  • https://www.humani.st Luke Hoersten

    Just like to point out Disco which only adds to the coolness of this idea.

  • https://www.humani.st Luke Hoersten

    Tony Arcieri, creater of Reia, a Python-like scripting language built on the Erlang VM, has written a great article about single assignment variable myths. He definitely clears up a lot of things I had trouble explaining in my article.

  • http://woweu.tazu.nl wow goud

    Luke, I'm just curious, do you happen to live near Antwerp (Belgium) ?

    The name 'Hoersten' was mentioned during one of my employer's recent gatherings and I was curious if it's you. You know, the world's a small place sometimes. :-)

  • https://www.humani.st Luke Hoersten

    That is not me though my family is from Germany. If we've come as far as the US I imagine we've spread to Belgium as well.

  • http://satelite-keys.blogspot.com free fta satellite keys

    Has read with the pleasure, very interesting post, write still, good luck to you!

  • Pingback: I have seen the future, and it is copy-on-write « Hashed Bits

  • http://www.club-penguin.org/club-penguin-cheats/club-penguin-unlock-books-codes-and-cheat-code-give-away.html clubpenguincheatcodes

    In Erlang it is perfectly legal to have *different* functions with the same name but with different arities, so if you want to reference a function uniquely you need to specify the arity. Of course, in some limited situations this may not be necessary but in the general case it is.

  • http://www.club-penguin.org/club-penguin-cheats/club-penguin-unlock-books-codes-and-cheat-code-give-away.html clubpenguincheatcodes

    In Erlang it is perfectly legal to have *different* functions with the same name but with different arities, so if you want to reference a function uniquely you need to specify the arity. Of course, in some limited situations this may not be necessary but in the general case it is.

  • http://pichis-blog.blogspot.com/ Hynek (Pichi) Vychodil

    Erlang always copy data because strict process isolation and soft-realtime GC.

  • EStau

    nice

  • EStau

    nice

  • Pingback: Cool game programming languages for 2010 « Ahmed Ali from Ravi Road

  • Pingback: 50 + Dofollow high page rank links to direct posts