Erlang: The problem with being "new"
2nd of June 2008So you spend 5/10 years learning X, but start to think it might not be the best solution for every problem, You have heard Y is good for solving your new problem, so you give it a shot, skim over some blogs, maybe even spend an afternoon learning it. After while you get fustrated, things that you can do easily in X are suddenly hard and fustrating in Y, you cant recognise the wierd interface. Conclusion: it must be a terrible language / application / etc.
One of the most popular opinions I find on Erlang is that it looks like an amazing platform, but not a very nice language. Since I had a similiar opinion when coming to Erlang (from primarily PHP and Java), I thought I would post comparable snippets to show why I now enjoy programming in Erlang.
Problem:
Code a simple chat message handler, define a simple function that takes parsed input, and calls the function relating to that command. if the message isnt one of the valid format, throw an exception. The 3 valid inputs in both languages are :
Erlang : PHP :
handle({enter,"user"}) handle(array(ENTER,"user"))
handle({leave,"user"}) handle(array(LEAVE,"user"))
handle({message,"user","message"}) handle(array(MESSAGE,"user","message"))
PHP Solution :
(check the comments for Jon Hohle's version, it is much more elegant)
define("ENTER", 1);
define("LEAVE", 2);
define("MESSAGE", 3);
function handle($cmd)
{
if(is_array($cmd) && ($count = count($cmd)) > 1)
{
if($cmd[0] == ENTER && $count == 2)
return enter($cmd[1]);
else if($cmd[0] == LEAVE && $count == 2)
return leave($cmd[1]);
else if($cmd[0] == MESSAGE && $count == 3)
return message($cmd[1],$cmd[2]);
}
throw new Exception('Invalid Message');
}
Erlang Solution :
handle({enter,User}) -> enter(User);
handle({leave,User}) -> leave(User);
handle({message,User,Msg}) -> message(User,Msg);
handle(_) -> throw("Invalid Message").
The example illustrates a small benefit of pattern matching which is at the heart of Erlang. Some things new users might see as 'warts' are often powerful features, and a few hours introduction into a language is never going to match the cumulative experience gained in years of writing applications.
Comments
Tom Wesson
Jun 1, 08function handle($cmd) { try { switch ( $cmd[0] ) { case 1: return enter ( $cmd[1] ); case 2: return leave ( $cmd[1] ); case 3: return message ( $cmd[1], $cmd[2] ); } } catch(e) { } throw new Exception ( 'Invalid Message' ); }Justin
Jun 2, 08ENTER = 1 LEAVE = 2 MESSAGE = 3 def handle_enter(user): print 'enter', user def handle_leave(user): print 'leave', user def handle_message(user, msg): print 'message', user, msg handlers = { ENTER: handle_enter, LEAVE: handle_leave, MESSAGE: handle_message, } def handle(cmd, *args): f = handlers.get(cmd) if not f: raise Exception("Invalid Message") return f(*args)It takes a little more work up front, but you can see the actual handler function is super simple. The erlang approach is nice too, their automatic creation of atoms makes you have to do less work. For python a common thing is to just use strings for the message types, then you don't even need the dictionary.
Anonymous
Jun 2, 08>
...handle({message,User,Msg}) -> message(User,Msg);
handle(_) -> throw("Invalid Message").
Is this last line idiomatic Erlang?
Side note: Your blog is very hard to read in Opera.
Dale
Jun 2, 08the throw itself is not idiomatic, I would usually leave it out and imagine most erlangers would, without it erlang would throw its own exception that looks like
which is easily understandable, I occasionally throw exceptions when a function can be wrapped in transactions / first class functions and I want to be very specific about point of failure. its usually not needed though, I mostly put it in to match the PHP
the _ is just a match all / dont care expression
**edit : fixed opera, must remember to validate new posts
josh
Jun 2, 08Michael Mrozek
Jun 2, 08Jon Hohle
Jun 2, 08define('ENTER', 1); define('LEAVE', 2); define('MESSAGE', 3); function handle(array $cmd) { switch (array(array_shift($cmd), count($cmd))) { case array(ENTER, 1): $handler = 'enter'; break; case array(LEAVE, 1): $handler = 'leave'; break; case array(MESSAGE, 2): $handler = 'message'; break; default: throw new Exception('Invalid Message'); } return call_user_func_array($handler, $cmd); }
You get the array check for free with argument type hints, and the array size checking is done by the switch. In fact, adding a new case is about the same amount of code as your Erlang example (though the boiler plate is much larger) - just one additional line. The arity check is explicit, however, unlike the Erlang example, where arity is implied by pattern matching.Don't get me wrong; I'm not trying to say PHP is as flexible or convenient, or as elegant as Erlang. I would never say PHP is a beautiful language. Your PHP example just doesn't take advantage of the available language features.
Jon Hohle
Jun 2, 08pretags were unnecessary.Dale
Jun 2, 08Thats certainly the most elegant PHP version ive seen. It was never an intention to make a PHP vs Erlang argument, I still like PHP, and dont think there is a language I have used that isnt the best in some situations, Its just a shame to see people dismiss languages like Erlang / Haskell etc purely due to being unfamiliar with the syntax.
(I will put instructions / rewrite the formatter for code in comments tomorrow, this is a new blog, and its obviously not very good)
James Justin Harrell
Jun 2, 08I really doubt Erlang is anywhere near as terrible as PHP, but this example seems pretty meaningless to me. There are many problems which would make PHP appear just as superior to Erlang.
Jon Hohle
Jun 2, 08From what I've seen, I really like Erlang's syntax; though I must admit, I really know nothing about the language. Hopefully more blog posts like this one will convince me to look into it further ;)
Dale
Jun 2, 08Jon, good to hear, it really is an amazing platform wrapped in a pretty nice little language.
Post a Comment