What Sucks About Erlang
There are the languages everyone complains about, and there are the languages no one uses.
Having said that, it's time to whine about my favorite language I use quite extensively. Erlang, I love ya, but we need to have a word.
Basic Syntax
Erlang is based originally on Prolog, a logic programming language that was briefly hot in the 80's. Surely you've seen other languages based on Prolog, right? No? Why not? Because Prolog sucks ass for building entire applications. But that hasn't deterred Erlang from stealing it's dynamite syntax.
The problem is, unlike the C and Algol based languages, Erlang's syntax does away with nested statement terminators and instead uses expression separators everywhere. Lisp suffers the same problem, but Erlang doesn't have the interesting properties of a completely uniform syntax and powerful macro system to redeem itself. Sometimes a flaw is really a strength. And sometimes it's just a flaw.
Because Erlang's expression terminators vary by context, editing code is much harder than conventional languages. Refactoring -- cutting and pasting and moving code around -- is particularly hard to do without creating a bunch of syntax errors.
Consider this code:
blah(true) ->
foo(),
bar();
blah(false) ->
baz().
Lets say I want to reorder the branches:
blah(false) ->
baz();
blah(true) ->
foo(),
bar().
Or change the order which foo() and bar() are called.
blah(true) ->
bar(),
foo();
blah(false) ->
baz().
What's the problem? Note in each example the bar() lines, they have a different character ending each line: bar(); bar(), bar().
In Algol based languages the statement terminators are the same everywhere (usually semi-colon, newline or both). The Javascript version:
function blah(flag) {
if (flag) {
bar();
foo();
} else {
baz();
}
}
Erlang expression separators vary context to context and it's simply more mental work to get right.
If Expressions
You might think if branching as something that no language could ever get wrong. Doesn't seem possible does it? I was young once too.
The first problem is that every time an if executes it should match at least one of the conditional expression branches. When it does not, an exception is thrown.
In this example:
if
X == foo ->
foo();
X == bar ->
bar()
end
X must be foo or bar, or an if_clause exception is thrown.
This sorta makes some sense since the if's aren't statements like in C language family, they are more like the C ternary operator (x == foo ? foo() : bar()) and so must return a value to the caller.
The problem is it prevents simple code like this:
if
Logging ->
log("Something happened")
end
Because if Logging is false, the if throws an if_clause exception!
Instead you are forced to do something like this:
The only purpose of the
if
Logging ->
log("Something happened");
true -> ok
end
true -> ok line is to give it an else condition to match. That weird taste in the back of your throat? It's probably vomit.
Erlang ifs could be so much more useful if it would just return a sensible default when no conditionals match, like an empty list [] or the undefined atom. But instead it blows up with an exception. If Erlang were a side-effect free functional language, such a restriction would make sense. But it's not side effect free, so instead it's idiotic and painful.
It gets worse. You cannot even call user defined functions in if conditional expressions! For example, this won't even compile because of the call to user defined should_foo(X):
should_foo(X) ->
X == foo.
bar() ->
if
should_foo(X) -> % compile error on this line!
foo();
true -> ok
end.
This limitation is due to Erlang's "when clause" pattern matching engine, which needs certain guarantees from the expressions for static optimization. Erlang allows a subset of the built-in functions (BIFs) in conditional expressions, but no user defined functions can be called whatsoever.
How can a language have butchered the if and still be useful? Well, fortunately case expressions in Erlang are powerful and damn useful, and a decent substitute for most uses of if:
case should_foo(X) of
true -> foo();
false -> ok
end
But like if expressions, case expression also have the limitation that it must match at least one conditional or an exception is thrown. Bleh.
You Say String of Characters, I Say List of Integers
The most obvious problem Erlang has for applications is sucky string handling. In Erlang, there is no string type, strings are just a list of integers, each integer being an encoded character value in the string.
It's not all bad. It has the benefit of taking the same built-in list operations, libraries and optimizations and reusing them for string processing. But it also means you can't distinguish easily at runtime between a string and a list, and especially between a string and a list of integers.
From the Erlang Console you get this:
1> [100,111,103] == "dog".
true
Erlang string operations are just not as simple or easy as most languages with integrated string types. I personally wouldn't pick Erlang for most front-end web application work. I'd probably choose PHP or Python, or some other scripting language with integrated string handling.
Functional Programming Mismatch
Erlang has been a great fit for CouchDB, a network database server. Once I got over Erlang's weirdness and accepted its warts, I almost couldn't imagine using anything else. So much of the code seems to want to be expressed in a recursive, functional manner and the lightweight, shared nothing concurrency is a great match for network servers and database internals. The code is typically much more compact, elegant and reliable than it would be in more conventional languages.
But when it came time to write the test suite code for CouchDB, I found Erlang to be needlessly cumbersome, verbose and inflexible.
Immutable variables in Erlang are hard to deal with when you have code that tends to change a lot, like user application code, where you are often performing a bunch of arbitrary steps that need to be changed as needs evolve.
In C, lets say you have some code:
int f(int x) {
x = foo(x);
x = bar(x);
return baz(x);
}
And you want to add a new step in the function:
int f(int x) {
x = foo(x);
x = fab(x);
x = bar(x);
return baz(x);
}
Only one line needs editing,
Consider the Erlang equivalent:
f(X) ->
X1 = foo(X),
X2 = bar(X1),
baz(X2).
Now you want to add a new step, which requires editing every variable thereafter:
f(X) ->
X1 = foo(X),
X2 = fab(X1),
X3 = bar(X2),
baz(X3).
Erlang's context dependent expression separators and immutable variables end up being huge liabilities for certain types of code, and the result is far more line edits for otherwise simple code changes. For the CouchDB test suite I could feel the syntax fighting me at every turn. When I switched over to writing the tests in Javascript, things just flowed faster and edits were easier.
Erlang wasn't a good match for tests and for the same reasons I don't think it's a good match for front-end web applications.
Records
The "records" feature provides a C-ish structure facility, but it's surprisingly limited and verbose, requiring you to state the type of the record for each reference in the code.
Not once for each variable binding, but you must state the variable's type each and every place a member of the variable record is referenced.
-record(foo, {
a=0,
b=0,
c=0}).
bar(F) ->
baz1(F#foo.a),
baz2(F#foo.b),
F#foo{c=F#foo.c + 1}.
Each of those F#foo is a statement that says "I'm a record variable of type foo". And it's not enough to say it once. We must say it over and over again each time we use it.
Here is a more idiomatic use of records, which uses pattern matching to extract members into local variables:
bar(#foo{a=A,b=B,c=C}=F) ->
baz1(A),
baz2(B),
F#foo{c=C + 1}.
Which is still noisy compared to the equivalent in C:
struct foo {
int a;
int b;
int c;
}
foo bar(foo f) {
baz1(f.a);
baz2(f.b);
f.c += 1;
return f;
}
Another problem is records often feel like a tacked-on hack. They are compile-time static and record members cannot be added or removed at runtime, and don't fit with Erlang's otherwise dynamic nature.
Records are a compile time feature -- not a VM feature -- and are statically compiled down to regular tuples, with the first slot holding the record name atom, and each slot N + 1 corresponding to the Nth entry in record declaration. At compile time the record member references are converted to integer offsets for tuple operations.
The most noticeable problem is they aren't usable from the REPL command line, it won't accept record syntax without special steps and it still doesn't show you result records in record syntax. Same when debugging and dumping stack traces and symbols, the records always look like the tuples they are under the covers, requiring you to mentally decode which tuple slot corresponds to a record member. Erlang records give you most of the penalties of static typing with very little of the benefit.
Give me memory, or give me death!
Update: On OS X with the most recent Erlang VM (R12B-1, emulator version 5.6.1), I can no longer reproduce this problem. Yay!
With CouchDB we discovered the hard way how Erlang handles memory allocation errors from the OS:
exit(1);
When the VM cannot get memory from the OS, it just commits hara-kiri. It doesn't just kill the virtual Erlang "process" that needs the memory. It kills the whole VM, taking along any child OS processes with it. But at least it's an honorable death.
See for yourself, try this at the Erlang console:
So no problem you might think, given Erlang's robust, fail-fast and restart nature, it will restart itself automatically and barely miss a beat. Well, that's what I thought, but then I'm generally a positive guy.
Eshell V5.5.3 (abort with ^G)
1> <<0:429967295>>.
beam(722,0xa000d000) malloc: *** vm_allocate(size=1782579200) failed (error code=3)
[....snip stack trace....]
Crash dump was written to: erl_crash.dump
eheap_alloc: Cannot allocate 1781763260 bytes of memory (of type "heap").
Abort trap
Nope, Erlang won't restart itself automatically, that's something you have to build all by yourself. The only solution we've found is to create a parent watchdog process to monitor the VM and restart it if it crashes.
The built-in "heart" child OS process, whose job it is to monitor for an unresponsive Erlang VM and restart it, is also killed when the VM exits. So we have to roll our own "restart the dead VM" solution and deal with cross-platform issues providing something I'm still shocked Erlang can't handle itself.
Code Organization
The only code organization offered is the source file module, there are no classes or namespaces. I'm no OO fanatic (not anymore), but I do see the real value it has: code organization.
Every time time you need to create something resembling a class (like an OTP generic process), you have to create whole Erlang file module, which means a whole new source file with a copyright banner plus the Erlang cruft at the top of each source file, and then it must be added to build system and source control. The extra file creation artificially spreads out the code over the file system, making things harder to follow.
What I wish for is a simple class facility. I don't need inheritance or virtual methods or static checking or monkey patching. I'd just like some encapsulation, the ability to say here is a hunk of data and you can use these methods to taste the tootsie center. That would satisfy about 90% of my unmet project organization needs.
Uneven Libraries and Documentation
Most of core Erlang is well documented and designed, but too many of the included modules are buggy, overly complex, poorly documented or all three.
The Inets httpd server we've found incredibly frustrating to use in CouchDB and are discarding it for a 3rd party Erlang HTTP library. The XML processor (Xmerl) is slow, complicated and under documented. Anything in Erlang using a GUI, like the debugger or process monitor, is hideous on Windows and pretty much unusable on OS X. The OTP build and versioning system is complicated and verbose and I still don't understand why it is like it is.
And crufty. I know Erlang has been evolving for real world use for a long time, but that doesn't make the cruftyness it's accumulated over the years smell any better. The coding standards in the core Erlang libraries can differ widely, with different naming, argument ordering and return value conventions. It's tolerable, but it's still there and you must still deal with it.
Erlang Really Sucks?
Yes, in all the ways I just described and more that I didn't.
But also no. Erlang is amazing in ways it would take a whole book to describe properly. It's not a toy built to satisfy the urges of academics, it's used in successful, real world products. But there is a good chance that Erlang just is not a good match for your uses. This list isn't meant to put down Erlang, but as an honest assessment of it's weaknesses, which I think aren't discussed enough.
Posted March 9, 2008 3:46 PM
Comments
Thanks Damien, it's nice to read thoughts about what's not cool about Erlang.
Lawrence Oluyede, March 9, 2008 5:37 PM
Hi Damien,
Agree completely with all of your points. Just a note though -- in many cases where you are doing a bunch of stuff like
f(X) ->
X1 = foo(X),
X2 = fab(X1),
X3 = bar(X2),
baz(X3).
it would be better to use a fold on a list, that way you end up not needing to name the intermediate variables. Since you can always use the module, function, args way to invoke an erlang function, you could do a fold on the list [foo, fab, bar, baz] which would make it easy to add more functions.
Vijay Chakravarthy, March 9, 2008 5:48 PM
I think the problem with Erlang is that it's more than 20 years old and for most of this time haven't been exposed enough to developer community at large. It's like raising a child in a cellar for all its childhood and don't let it interact and learn from his/her peers. Erlang definitely needs something like Python's PEPs.
Meanwhile I am looking forward to see what comes out of efforts like LFE.
Kamyar Navidan, March 9, 2008 6:40 PM
Have you tried daemontools for restarting the Erlang process? http://cr.yp.to/daemontools.html
I wonder if you could maintain your Erlang code as a set of S-expressions. Then use a few Lisp functions to write out the final destination syntax to a file.
CS, March 9, 2008 6:50 PM
For refactoring have you tried distel? I found it made life a fair bit easier to use it when hacking Erlang. For lisp programmers it is a bit like slime for erlang.
cheers.
msingh, March 9, 2008 7:32 PM
Prolog is still better than Java. At least it had the intention to do something useful, while not focussing on machine code optimization. Java alas, does nothing good, it's harder than C++ to program, and the machine code just plain sucks, indeed it doesn't even do machine code, but just some useless virtual machine interpreter code, even BASIC can do that better!
Mika Heinonen, March 9, 2008 7:52 PM
You raise some very good points. Erlang does need to address some of these warts to gain wider acceptance.
However, I'm curious why you think the expression oriented syntax (a la Lisp is a bad thing.
I don't know how much you've worked with Lisp, but to me, the issue is trivially supported by the code editor. Emacs and its various cousins have solved this for Lisp s-expressions to the extent that editing any other language looks clunky (Just contemplate transpose-sexps in any other syntax).
There's a lot of merit to Erlang adopting a s-expression syntax like the LFE work which has appeared recently. Your other points would still need to be addressed though.
ram k., March 9, 2008 7:59 PM
* Basic syntax. Different terminators are not C-ish but I don't think that matters much. Except maybe when you're switching between languages very often during the day.
* As you pointed out: the if syntax only evaluates guard sequences. In the mildly complex code I am looking at right now (about 10 modules) there is none present - I don't think I've ever used one during about one year of Erlang development.
* Single-bind variables: as Erlang's default stacktraces force you to write many small function I never found that a problem.
* Records: preprocessor structures with a nasty syntax where most introspections also need macros. I agree.
* Heart dying: should not IIRC but I've never operated an Erlang application.
* Namespace: see the package module. It requires you to import everything which is in the default namespace (.) though. Or use the prefix convention.
* Module quality: I personally never used xmerl or anything GUI-ish (the examples I looked at kind of spoke for themselves) but you're right the quality of the modules varies. OTP version handling is not really concise documented, that's all (IMHO).
IMHO Erlang is a special purpose language (which is why I do not really understand the hype around it now). For everything beneath it's scope it get more and more difficult to produce concise solutions.
yawn, March 9, 2008 9:34 PM
int f(int x) {
x = foo(x);
x = fab(x);
x = bar(x);
return baz(x);
}
isn't good code to begin with.
int f(int x) {
return baz(bar(foo(x))
}
is better in either language, and lets you make your change easily. Why give names to the intermediate states? It only creates more conceptual entities to track later. This is presuming you've named the functions well of course.
Greg M, March 9, 2008 10:31 PM
"return baz(bar(foo(x))" increases line noise and possibly hinders comprehension, so use with care.
"* Heart dying: should not". Well, it does :-)
"tried daemontools": for custom deployment they are nice, but we don't want to bundle them.
Jan, March 9, 2008 11:35 PM
Of the above comments I can only see two which are major actual problems
The rescrition on Guards and if conditions is definatly cumbersom. There should be some way to declare user defined functions as safe to use in guards. Honestly you should be able to do this, and if you lie well then you've brought trouble on your own head.
Some milage may be gained by using macros in place of user defined functions here (I could be wrong I'm still very new to Erlang and havn't tried this).
The trouble with records struck me as a flaw immediately (on the first reading of the manual) and does smell like it was bolted on.
There is a few other bolted on features you didn't mention such as in process error handling with catch and throw.
Konrad, March 10, 2008 1:22 AM
I basically agree with all your points. Yes they are warts - sigh.
The complaint that heart doesn't restart the VM when it runs out of memory I'd consider just a regular bug. Report it! Of course the VM should be restarted by heart if it runs out of memory and calls exit(1)
On a sidenote - I firmly believe that exit(1) is the right thing to do when malloc() returns NULL
The alternatives are hideous and leads nowhere.
klacke, March 10, 2008 5:06 AM
Re: klacke saying that exit(1) is the right thing...
It really might be, distasteful as that is. Since you aren't explicitly allocating or deallocating memory, how would you handle an OutOfMemory exception, anyway?
We (Opera) run on small devices and every single allocation is prepared for failure, and we do our best to handle the situation with grace.
But I cannot imagine how we would do this in Erlang. Without having a heap/stack distinction, with all of the intermediate objects, with all of the recursion... running out of memory is really a nasty problem. :)
Maybe some kind of compile-time guarantees that certain parts of the code would run in constant space... is that even possible? Even without recursion? Or certain "big objects" that might live in a less-safe place... no, these are really hard problems, Damien. :)
Otherwise, I totally agree with everything you said. And it kills me because most of this stuff is so silly, so surface! It would still (to me at least) feel like Erlang. I often think about writing a front-end that spits out Erlang, but... never quite get around to it. :)
Chris Pine, March 10, 2008 5:37 AM
Nice post!
If I hadn't been using Erlang before and wanted to check it out. Then I would get rid of those silly ideas here and now!
Tobbe, March 10, 2008 7:35 AM
Chris Pine wrote:
>We (Opera) run on small devices and every single >allocation is prepared for failure, and we do our >best to handle the situation with grace.
grace? what is that then. Writing a log entry? That'll also probably fail since it probably will have to allocate to format the print buffers or something. Pre allocated buffers to use in case of memory exhaustion. Uhhh.
The Linux OOM killer - is that a good idea. I think not.
>But I cannot imagine how we would do this in >Erlang. Without having a heap/stack distinction, >with all of the intermediate objects,
It would actually be perfectly doable to choose one or several processes based on some heuristics such as number of reductions, heap size, stack size, unprocessed messages in the mbox etc and then just kill that/those processes and thereby releasing the memory held by just those - possibly - offending processes. Very similar to the OOM killer.
So in Erlang this would be doable as opposed to say a C or a Java program. But I still think it's a bad idea. Better then to exit(1) and let heart restart the daemon.
klacke, March 10, 2008 7:38 AM
Yawn, yawn. You have pet peeves like most programmers. How very interesting(irony intended).
A non, March 10, 2008 9:02 AM
klacke asked:
> grace? what is that then. Writing a log entry?
In Opera's case, or in some hypothetical Erlang?
In Opera's case, we stop and look for memory we can free up (ecmascript runtime gc, cached images, etc).
But my point was that only the app can know how to gracefully handle OOM situations, and can only do something about it if the app is in charge of the memory.
Though you bring up the idea of killing possibly-offending processes... what if the app could declare certain processes as OOM-expendable? Then in an OOM situation, Erlang could start killing off those, and only exit(1) if there are none of those left.
Since the app was able to choose (ahead of time, of course) *which* process(es) to kill, wouldn't that be better than just exiting? Seems like it would not be too much trouble to implement, either, and since it's opt-in only it would play well with existing programs.
Chris Pine, March 10, 2008 10:54 AM
Wrt heart: this is really surprising to me since we run heart and we see it restart Erlang all the time. kill -9, erlang:halt (1), etc. all cause restarts. One question: have you set the HEART_COMMAND environment variable?
Paul Mineiro, March 10, 2008 1:07 PM
FYI, Erlang does have hierarchical namespaces that correspond with source file locations in subirectories (e.g. hammer.json:serialize() that corresponds with what you wrote in "hammer/json.erl").
partdavid, March 10, 2008 6:18 PM
On "if"--would there be an issue if "if" was named "guard" (since that's what it does, evaluates guard clauses, not any conditional expression); and if you could "if ... is" as a synonym for "case ... of"?
partdavid, March 10, 2008 6:49 PM
" heart and we see it restart Erlang all the time"
Jan, March 10, 2008 7:17 PM
(Now the last commet got butched)
" heart and we see it restart Erlang all the time"
we use heart, but in case of a failing memory allocation the erlang vm and all of its processgroup get wiped out. including heart. "just" killing erlang works like a charm.
Anonymous, March 10, 2008 7:20 PM
vim? emacs? or ???
linux? windows? or ??
:-)
zj, March 10, 2008 9:59 PM
"Yawn, yawn. You have pet peeves like most programmers. How very interesting (irony intended)."
I think you mean sarcasm. What kind of person takes the time to read an article and then bother to leave a comment like this. Very strange.
Noah Slater, March 10, 2008 10:19 PM
As far as what to do when an allocation fails, fetchmail waits a bit for some less important process to free up some memory, and tries again. Perhaps not the right choice for a soft real time environment.
Ronald Pottol, March 10, 2008 11:03 PM
I'm curious as to why you think having to add files for modularity is a problem:
"Every time time you need to create something resembling a class (like an OTP generic process), you have to create whole Erlang file module, which means a whole new source file with a copyright banner plus the Erlang cruft at the top of each source file, and then it must be added to build system and source control."
I've been following the one class, one file rule (in C++ development) for several years, and find that it actually helps me to navigate the codebase when file names correspond to single classes. It also keeps the file size small, and class interfaces fit in just one modern screenful (at least most of the time).
Jaakko Haapasalo, March 13, 2008 2:58 AM
11. Thou shall not doubt open source software.
Banador, March 13, 2008 6:24 PM
The discussions on the erlang-questions list pointed out that a simple alternative to 'if' for your debugging example is:
DebugOn andalso log(Something),
provided that log/1 returns 'true' it can be used in any construct where andalso makes sense.
Jay Nelson, March 14, 2008 12:42 PM
The side swipe against prolog mar what is an otherwise interesting and thoughtful article.
Erlang definitely got a leg-up from prolog and declarative programming languages in general.
No doubt when the author(s) of Erlang wanted to build a new language they chose to do it in a language that easily supports building new languages.
I wonder if the author has tried using the definite clause grammar (DCG) feature in prolog? It is a very elegant way of building parsers for domain specific languages.
Another debt owed to prolog is the pattern matching algorithm (unification). The use of unification is one of the reasons that Erlang manages to be so terse and expressive.
Most of the problems the author describes with Erlang syntax were introduced in Erlang in an attempt to shoe-horn imperative features into a syntax that was designed for a declarative language.
There are plenty of things that make prolog completely impractical for serious software development (no arguments on that point) but the lack of a regular syntax is not one of them.
Erlang is a well chosen compromise between expressiveness and terseness of logic programming languages and the practicalities of building distributed imperative software for current networks/hardware.
Declarative by nature, April 5, 2008 11:31 PM
I agree with nature for the most part but I believe Damian is trying to explain why Erlang for the most part isn't a replacement for front loaded web apps of traditional design as much as it's a replacement for network dependent asynchronous processes to such like a database or distributed record store. He explains that aspects which make it powerful for one make it cumbersome for the other and I appreciate that take. I also just want to add that it makes sense to drop prematurely formed ideals of programming until the methodology has been fully consumed.
Pedram, November 24, 2008 6:31 PM
Regarding:
if
Logging ->
log("Something happened")
end
What about Joe's macro in his book:
-module(m1).
-export([start/0]).
-ifdef(debug).
-define(TRACE(X), io:format("TRACE ~p:~p ~p~n" ,[?MODULE, ?LINE, X])).
-else.
-define(TRACE(X), void).
-endif.
start() -> loop(5).
loop(0) ->
void;
loop(N) ->
?TRACE(N),
loop(N-1).
Hans Schmid, December 22, 2008 6:56 PM
The post isn't entirely correct regarding Algol and semicolons. Algol 68 included collateral clauses that separated statements with commas, in addition to the semi-colon separators we're used to. The purpose was to express potential concurrency in a program by relaxing the sequencing requirement imposed by the semicolon. Saying "A, B; C" in Algol would mean statement A and B can execute in any order relative to each other, so long as both are complete before C executes. If you're going to invoke Algol and other historical things that most of your readers aren't familiar with, you might as well get the story right. Algol did NOT have a single consistent terminator as you claim.
MJS, February 9, 2009 3:14 AM
@yawn
Thanks for the package module hint! I didn't know about that...
@Damien
You have some valid points.
- Records don't work for me, and I don't use them unless I use mnesia
- if statement. I tend to only rarely require an if statement, using the case statement and pattern matching instead.
- string support. It would be nice to see some better string support...
P.S. If you ever read this, thanks for CouchDB, and the side effect of getting more exposure for Erlang!
Benjamin, February 11, 2009 4:32 PM
I can find the prayer I want. I thank God for this website.
Malcom, May 12, 2009 1:49 PM
Agree with Benjamin: I (nearly) never uses if-statements. I uses case statements and pattern matching, as it's much more usefull. And the use of guards in function heads to.
Cleaning up the libraries would be a good idea though.
Kamyar Navidan, Erlang has been exposed to really good programmers, and real time usage in real production. So that in not one of Erlangs problems. Some late addons, like annonymous functions and records is obvious. But has come to life becouse of later whishes. But they are still usefull, but a better syntax would not been a bad idea. But we have them now.
Pascal uses semicolon as a statement separator, not to end statements. So "if (test) then a(); then b();" will generate an error (a tip: remove ";" after "a()").
Yes, Pascal is also a member of the Algol family. You prob. ment "Of the C family"
By the way, thanks for CouchDB and the exposure of Erlang. The way to go! :)
jxn, May 29, 2009 3:16 PM
I really enjoyed from this article. I am very new to Erlangs wondering if it is a good choice for a multi-purpose high-speed digital receiver. Reading the introduction chapter of Francesco & Simon's book I was so excited about the language that I almost feel that I found the answer, but reading your respectful opinions make me to think twice, mostly because our team members are all used to C/C++ family of languages. Thanks you again.
Askar Samadi, July 4, 2009 3:25 PM
Look what you have done!
Put stronger qualifiers around your article, will you? Erlang really, obviously, is about inner qualities and then there are some very nice things on the surface, too. AND then there are warts. They may be repaired one day, or never, but people coming here on the hunt for information about Erlang as a language worth learning or not seem to get put of here for the wrong reasons.
So I suggest put "Erlang is great, but " before every sentence and intersperse jokes about other languages' syntaxes.
I mean it. Erlang needs more exposure, you are a main driver, people come here to get informed and run into your lament on valid but secondary issues in the fine print.
Brainiac 5, July 5, 2009 8:04 PM
Erlang functions and processes are cheap.
Solve your problem by divide into small functions and small processes.
Don't use if, case too much.
Use bit string replace for string.
yangho, July 16, 2009 10:17 PM
Erlang R13B01 (erts-5.7.2)
1> >.
0,...>>
2> >.
** exception error: a system limit has been reached
3>
For variables, use just foo(fab(bar(X))) :)
If you really need, give them descriptive names, if you really want some variables witn number use multiplies of 10, or use some abstraction with foldl:
lists:foldl(fun(Fun,XP) -> Fun(XP) end,
X,
[fun foo/1, fun fab/1, fun bar/1]).
About ,;., it is matter of time and getting exprience with it. these are costs of not having curly braces. Ulf Wiger created syntax transfor for indentation style nesting like in Python.
If expressions, i use it very rearly (and check always in book, i use correct syntax), 100 times more often i use case.
Packages can be constructed using dots in module names.
Records sometimes sucks, but not because you need to write record name or strange syntax (which is good imho), but because of code upgrades and changing record definition on live system with multiple versions on different nodes. It isn't very easy now. One can use dicts, parametrized modules for retriving proper fields or wait for something called "slice", they are space efficient like a record + O(1), but can be extended dynamically with cost of slightly slower access O(log(N)), this can by about 3 times slower for avarage sized splices than records.
Life is not easy, and many Erlang components need to improved. Mayby even few thing from Erlang should be removed, becuase adding new things is easy, removing should be done as early as possible.
Witold Baryluk, August 13, 2009 11:42 AM
Thanks for new information. Though I still have some questions but I hope I'll find the answers to them. As for me I'm just a beginner. You know I've always envied the boys who are usually good at computer stuff and programming. But now I've decided to catch up with them. Thanks.
Violet, November 3, 2009 6:01 AM
typo:
Every time time -> Every time
Tom Wright, December 31, 2009 9:34 AM
I was just looking for some conditional expression syntax examples. Erlang seems to be quite the rabbit hole . . .
Ver, January 22, 2010 4:30 PM
I'm in complete agreement with the original post. Butt-ugly syntax. Let's see ... we want a functional language that will handle arbitrary anonymous tree-structured data. We want it to support fine-grained concurrency. And we want it not to suck. Syntactically, this sounds like one of the many concurrent LISPs.
It certainly would simplify things to be able to say that there will be no side-effects, and that operations happen in a deterministic order. But to get there from LISP, it seems you would mostly just be taking things away.
For instance, it seems to me that the source of unpredictable ordering in concurrent LISP comes from (a) having variables that exist in a context that can be accessed by multiple threads, and (b) having multiple expressions that are ready to go in parallel, without constraint on their ordering. [e.g. (and (fn1 'a) (fn2 'a)) -- both args to the AND can run in parallel, and both can potentially modify a.]
However, if you take either of these features away, the problem disappears. Get rid of (a) with some kind of single-assignment thing, like in Erlang, or get rid of (b) by always evaluating arguments sequentially. Solving (a) seems nicer from the perspective of maximizing concurrency. Add some pattern-matching, if you want.
No doubt there are some issues to deal with. But, jeesh, the Erlang syntax begs the question -- "couldn't we at least *try*?" I guess the key question is whether modifying LISP in these ways would make it more or less difficult to implement. For starters, all garbage would be lexically scoped. That's gotta be nice.
Jeff, February 15, 2010 7:48 PM
really enjoyed from this article. I am very new to Erlangs wondering if it is a good choice for a multi-purpose high-speed digital receiver. Reading the introduction chapter of Francesco & Simon's book I was so excited about the language that I almost feel that I found the answer, but reading your respectful opinions make me to think twice, mostly because our team members are all used to C/C++ family of languages. Thanks you again.
Cool, March 24, 2010 7:10 AM
Take it from a beginner. Your syntax is screwed to hell when something like...
====
-module(mod_test).
-compile(export_all).
X=1.0,
Y=2.0,
Z=1.5,
case {X, Y, Z} of
{0, 0, 0} -> empty_vector; % empty_vector is an atom
{A, A, A} -> all_the_same; % so is all_the_same
{X1, Y1, Z1} -> {X1 + 1, Y1 + 1, Z1 +1}.
end
====
results in errors such as
"syntax error before:X"
Maybe I'm just mentally retarded. -_-
Anonymous, March 31, 2010 6:11 PM
I need to say I like both - C and Algol and string of characters in one case mean list of integers. Maybe. I need to think about... smart article..
Dbuf.org, April 13, 2010 4:03 PM
@Jeff If you really want a LISP syntax try LFE, Lisp Flavoured Erlang, which gives you the best of both worlds.
@Anonymous Seeing a module, per definition, only contains function definitions then I would that the syntax error is very logical. I won't comment on the retarded bit. :-)
Robert Virding, April 19, 2010 4:51 PM
Regarding the basic syntax and records, I'm curious what anyone involved with Erlang would think of an alternate syntax? Not a complete transformation or different language like LFE or Riak, just a different syntax for Erlang files without the statement terminators, and smarter handling of record parameters. If anyone would be interested in a prototype of what that might look like, I put a project on GitHub named neaterl.
Walt Woods, June 10, 2010 12:39 AM
The syntax of Erlang outright gives me the heebie-geebies. Am I saying this as an Algol syntax fan? Well, yes I'm an Algol-syntax programmer today. But I'm not a fan of their syntaxes either.
I bite back some of that syntax-revulsion by reminding myself it reminds me this is a different style of language (i.e. functional).
You really need to coerce yourself to make the complete transition and layout your code Erlang style rather than trying to keep it Algol like.
Consider your editing example. When you put clauses like ';' on the end of lines, it does indeed introduce editing headaches.
So try an alternate styling; make continuations into prefixes rather than postfixes.
This has an additional advantage:
When you are skimming/scanning code, and a statement catches your eye, you don't have to backtrack to the last end-of-line to figure out the context of any given line.
You might counter that "yes, but to see what happens next I have to look at the next line".
This is true, but that information will be clear and visible: that is, you already know where to look, you don't have to find it.
I picked this up from an old DBA, and it stuck ever since. It took a while getting used to it. The impulse to type "something," is strong - you have to remind yourself "it is a PRIMITIVE, it should go at the beginning of a line!"
Oliver 'kfs1' Smith, June 28, 2010 1:17 PM
It would be nice if Erlang would take the syntactic sugar step of
where "(>)" or ">>" if it looks cleaner, is defined as forward the result of the previous call, or in the case of the first "->", the parameter list being used here.
Oliver 'kfs1' Smith, June 28, 2010 5:49 PM
Quote:
f(X) ->
X1 = foo(X),
X2 = bar(X1),
baz(X2).
Now you want to add a new step, which requires editing every variable thereafter:
f(X) ->
X1 = foo(X),
X2 = fab(X1),
X3 = bar(X2),
baz(X3).
End Quote.
This "ripple effect" can be avoided by a better choice of name:
f(X) ->
X1 = foo(X),
X1_1 = fab(X1),
X2 = bar(X1_1),
baz(X2).
Further insertions may result in the sequence:
X1, X1_0, X1_0_1, X1_0_2, X1_1, X1_2, X1_2_1, X2, X2_1, etc.
It really isn't as much of a problem as you make out...
Uncompetative, August 16, 2010 11:10 AM
I can tell that you understand this topic, well written and nice job.I'm going to be tweeting this to my followers as I think it's pretty important.I'm thinking this is the best post I've read on your blog yet.I'll be back for sure, excellent stuff.
ubot examples, August 27, 2010 2:06 PM
I must say I don't really understand all this wailing (both here and elsewhere) about having to rename variables when adding/removing steps. I usually find that this is the least of my problems when modifying code, it might be the most visible change needed, but hardly the most difficult.
It also has the benefit of giving you complete control of which values you use, which is a Big Win when writing code which is more realistic than these examples.
Robert Virding, August 30, 2010 5:04 AM
Post a comment