Wednesday, September 13, 2006

Erlang MySQL Driver, Reloaded

In my quest to make ErlyDB a top-notch database abstraction tool (since I'm planning on using it myself, I wouldn't want it to be any less :) ), I have spent the past few days improving the Yxa MySQL driver for Erlang that I obtained from Process One to bring it up to par with ErlyDB's needs. I ended up rewriting much of the driver's internals as well as adding a bunch of features and optimizations.



I created a Google Code project for this revamped driver, where I will make any future changes and bug fixes. You can access it at http://code.google.com/p/erlang-mysql-driver/.



(Btw, I even resisted getting pulled into a prolonged blog debate about Erlang's merits as a web development language as opposed to Ruby. Astonishingly, it looks like my last attempt at brainwashing all developers into becoming Erlang devotees has produced mixed results! I guess it's time to think about the next escalation in the propaganda war :) )



Here's a summary of my changes:




  • Added support for transactions

  • Added support for prepared statements (you can execute prepared statement in and outside of a transaction)

  • Added support for binary queries (this is the preferred way of sending queries because it's more efficient than using strings)

  • Rewrote the connection pooling mechanism to make it more efficient.

  • Numbers and date/time values in result sets are automatically converted to their Erlang equivalents. Strings are treated as binaries.

  • Logging statements can now be instantiated lazily based on the desired logging level. This significantly reduces the overhead of logging, especially when debug level logging is disabled.

  • Other internal modifications.



Following is a short tutorial illustrating how to use the new features.



Create a MySQL database called "test" and the run the following script:



create table developer(
id integer auto_increment primary key,
name varchar(30),
country varchar(20),
created_on timestamp)
type=InnoDB;


(Setting the table type to InnoDB in necessary for transaction support.)



Here's some Erlang code showing how to use some of the new APIs.




%% Start the MySQL dispatcher and create the first connection
%% to the database. 'p1' is the connection pool identifier.
mysql:start_link(p1, "localhost", "root", "password", "test"),

%% Add 2 more connections to the connection pool
mysql:connect(p1, "localhost", undefined, "root",
"password", "test", true),
mysql:connect(p1, "localhost", undefined, "root",
"password", "test", true),

mysql:fetch(p1, <<"DELETE FROM developer">>),

mysql:fetch(p1, <<"INSERT INTO developer(name, country) "
"VALUES "
"('Claes (Klacke) Wikstrom', 'Sweden'),"
"('Ulf Wiger', 'USA')">>),

%% Execute a query (using a binary)
Result1 = mysql:fetch(p1, <<"SELECT * FROM developer">>),
io:format("Result1: ~p~n", [Result1]),

%% Register a prepared statement
mysql:prepare(update_developer_country,
<<"UPDATE developer SET country=? where name like ?">>),

%% Execute the prepared statement
mysql:execute(p1, update_developer_country, [<<"Sweden">>,
<<"%Wiger">>]),

Result2 = mysql:fetch(p1, <<"SELECT * FROM developer">>),
io:format("Result2: ~p~n", [Result2]),

%% Make some statements
S1 = <<"INSERT INTO developer(name, country) VALUES "
"('Joe Armstrong', 'USA')">>,

S2 = <<"DELETE FROM developer WHERE name like 'Claes%'">>,

%% Create a transaction
T1 = mysql:new_transaction(p1),
T2 = mysql:add_query(T1, S1),

%% You can execute prepared statements inside transactions
T3 = mysql:add_execute(T2, update_developer_country,
[<<"Sweden">>, <<"%Armstrong">>]),

T4 = mysql:add_query(T3, S2),
mysql:commit(T4),

Result3 = mysql:fetch(p1, <<"SELECT * FROM developer">>),
io:format("Result2: ~p~n", [Result3]),

%% Another way of doing a transaction
S3 = <<"DELETE FROM developer WHERE country='USA'">>,
mysql:transaction(p1, fun(T) ->
mysql:add_queries(T, [S1,S2,S3])
end),

Result4 = mysql:fetch(p1, <<"SELECT * FROM developer">>),
io:format("Result2: ~p~n", [Result4]),

%% Transactions are automatically rolled back if
%% any of their queries results in an error.
mysql:transaction(
p1, fun(T) ->
mysql:add_queries(T, [<<"DELETE FROM developer">>,
<<"bad bad query">>])
end),

Result5 = mysql:fetch(p1, <<"SELECT * FROM developer">>),
io:format("Result2: ~p~n", [Result5]),

ok.


Additional documentation is in mysql.erl.



In the next few days, I am planning to integrate these new features into ErlyDB. From some research I've done, I've learned that using prepared statements significantly lowers the load on the database. Given that the database is often a scalability bottleneck in web applications, I think it's important for ErlyDB to use prepared statements as much as possible.



I have done some testing, but given the large number of potentially destabilizing changes, I don't recommend this driver for production use at the moment. You can test it yourself to get comfortable with the code's stability or wait a month or two until it's more hardened.



Some notes about the driver's internals

When initialized, the driver spawns an Erlang process of type gen_server, called mysql_dispatcher, which maintains connection pools to MySQL databases. Each connection has an Erlang process. When the process crashes (i.e. the connection is lost), the dispatcher (by default) tries to reconnect to the database from a new process.


Erlang client processes communicate with the MySQL dispatcher using standard gen_server calls. This structure allows a large number of Erlang processes in a single VM to share relatively few database connections.


Prepared statements are actually prepared lazily per connection. When the user executes a previously defined prepared statement against a connection in which the statement hasn't been prepared, the dispatcher will issue the PREPARE call for the connection before executing the statement. If the execute call is part of a transaction, the dispatcher will issue the PREPARE call before the transaction begins.


If any statement inside a transaction results in an error, the driver automatically tries to roll back the transaction.

Friday, September 08, 2006

Where Are My Readers From?

Here's a geo map overlay view taken from Google Analytics for my blog's last 500 visits.



blog_visitor_map.png



As you can see, Erlang isn't just popular in Sweden :)



Ranked by number of visitors, the top 10 countries are USA (1312 visits), UK (188 visits), Germany (151 visits), Canada (135 visits), China (120 visits), Sweden (106 visits), france (94 visits), Australia (81 visits), Brazil (75 visits) and Netherlands (63 visits).



Where are you from?



Update: I made the high-res map downloadable.

Boston, End of Week One

This week flew by pretty fast, and unfortunately I haven't accomplished the improvements I had planned for ErlyDB. Next week, I will shift gears and start cranking out that ErlyDB code I have to produce.



So what did I do this week? I did some of blogging and emailing. I took a lot of walks around the Boston to familiarize myself with this town. I also took a bunch of pictures, most of which I put on flickr.



Here's my favorite picture from my walk earlier today in Boston Common. It's a beautiful statue of George Washington.



IMG_1648.JPG



(This great man wasn't thinking outside the thread -- he was thinking outside the Empire :) )



On the coding side, I spent a good deal of time revving the haXe remoting adapter I contributed to Yaws (my favorite web server :) ). Nicolas Cannasse, haXe's amazingly talented creator, has recently changed the haXe remoting protocol to improve the performace of the caching algorithm used to handle references to strings. In the previous implementation, the serialization of each string was preceded by a linear traversal of all previously serialized strings in search for a match. If a match was found, the index in the cache would be serialized rather than the string itself. This would lower the bandwidth cost of serializing the same string multiple times. Nicolas's improvement was to change the string comparisons to hash table lookups, which is far more efficient for messages with numerous strings.



My task was to make the same changes on the Erlang side. Unfortunately, I haven't touched the haXe remoting code in a while, so my knowledge of it was a bit rusty. The code is also rather complex, partly because it's written in Continuation Passing Style, which makes the parser capable of processing a message in chunks (also called stream-parsing) but also harder to comprehend. (The haXe remoting parser is based on the JSON RPC parser, which I hacked quite substantially.)



After some pretty frustrating debugging (both and haXe have changed since I last played with them), I finally got the code to a ready-to-ship state today. With a CVS commit (or two), the job was done.



I have no idea how many people are actually using this feature, but as both Yaws and haXe grow in popularity, I'm sure others will find it quite useful. haXe is rapidly becoming a great language for all sorts of GUI development, and combining it with a Yaws backend can make a pretty powerful combination (do I see haXe + Yaws powered massively multiplayer online Flash games on the horizon? :) ).



I'm happy that Klacke, Yaws's creator, was willing to let me add the haXe remoting feature to Yaws. It's a rather "exotic" feature, especially because I doubt many Erlangers use haXe. However, Klacke was interested in haXe and when I gave him the Erlang haXe remoting code, he made me a Yaws committer and gave me the green light to add it to the Yaws codebase (with the condition that I also write the documentation :) ).



Maybe at some point down the road I will offer Klacke another feature or two to add to Yaws :)



Now I can finally go back to the fun stuff: ErlyDB.

Thursday, September 07, 2006

The Best Erlang Propaganda You'll Ever See

Back in the old days (about 1 month ago), when my blog had about 10 visitors a day (most of whom came to download the XCode plugin for haXe I created), I fully enjoyed the unbridled freedom the blogging medium has given me in my writings about Erlang. My readers (reader?) were all interested in Erlang. Every statement I made about Erlang's strengths was taken as obvious. Justifying my arguments was as easy as saying 'duh.'



Times have changed.



My blog now gets over 1000 page views a day, and some days, when it's featured on reddit.com, it reaches over 5000 page views. With this deluge of new readers, I have suddenly found myself having to contend with an unfamiliar challenge: the Skeptics.



Many of my readers are very intelligent, experienced programmers. Some of them are knowledgeable about if not experts in just about every computer language you can imagine (well, maybe short of Brainf*ck). Erlang is different from many languages, and therefore many of my visitors write very good comments pointing out aspects of Erlang that they don't like or where they think Erlang falls short of other languages.



Like every language, Erlang has some shortcomings. Erlang is a tool, not a panacea. Erlang happens to be a very good tool for building scalable, fault-tolerant, distributed systems, which is primarily why I am so interested in it, but it's not a silver bullet. Depending on your needs, other languages are arguably better than Erlang: Perl for regexps and string processing, OCaml for raw performance, Haskell for its purity and type system, Ruby/Python/PHP for scripting and (some) database-driven webapps, Java for abundance of libraries (and programmers), C# if you're coding for the .NET platform, Prolog for logic programming, C/C++ for desktop programming, etc.



Still, I don't like dealing with skeptics.



You see, I'm at the helm of a well-greased Erlang hype machine, and I'm on a take-no-prisioners mission to recruit every programmer with an internet connection into the cult of Erlang. If you're a programmer, I won't rest until you think in Erlang; talk in Erlang; dream in Erlang. When I'm done with you, your life will be a list; your being will be a tuple; you will communicate to your family and coworkers by asynchronous message passing; your actions will be functions; your consciousness will run on pattern matching.



You will forget your objects. Your shared memory will become Mnesia.



To achieve this nefarious goal of mine, I decided it's time to bring out the big guns.



This is no fun and games anymore. This is war for the hearts and minds of programmers from faraway paradigms. I'm here at my command and control center, and I mean business.



Enough talk. It's time for action.



Without further ado, I present to you my secret weapon, as well as the best Erlang propaganda you'll ever see: The Erlang Movie.





(Try as hard as you can, I know you won't be able to resist hitting that "Play" button.)



...



Now that you've seen the Erlang Movie, we can resume rational discourse regarding the merits of this language. The only condition is that you have to blindingly accept everything I say. You also have to first run around the streets shouting at the top of your lungs "I've seen the light! It's called 'Erlang'!"



Deal? :)



...



Now back to serious writing: please don't take anything I've said here seriously!!!



Update: quick poll -- how many of you have watched the whole thing? :)

Wednesday, September 06, 2006

First Day in Boston on the "Job"

Yesterday was my first day as a resident Bostonian as well as a semi-unemployed Erlanger.



I must say that although my original impression of Boston wasn't very enthusiastic, I think this town will grow on me.



Boston is a college town in the truest sense of the word. In New York, everyone looks like he/she came from a different planet: people dress different, look different, speak different languages, and seeking different goals. In Boston, on the other hand, you feel like almost everyone is a student. I live somewhere between Boston College and Boston University, which makes the impression even stronger.



Because of its abundance of colleges, Boston feels like a very young town. In my advanced age of 26, I can't help but feel like I'm a TA or something :)



My new "office" is the Boston Public Library on Copley Square:



IMG_1573.JPG



(You're probably wondering what that blue cow is doing there. Apparently, the cows are all over Boston. Check out the rest of the set for more cow pictures.)



IMG_1588.JPG



Sometimes I don't get why many startups spend their money on renting office space when you can get a comfortable, quiet environment with good internet connectivity for free at the public library. Maybe it's that VC money thing :)



The Boston Public Library actually wins in the tech department over the New York Public Library for providing free Wi-Fi in the entire building, not just one room.



I didn't get much coding done yesterday, but today I'm hoping to finish implementing transaction handling in ErlyDB. It might take longer, though, so don't get your hopes up too high :)

Tuesday, September 05, 2006

Another Interesting Erlang Day on Reddit

Reddit readers seem to be very interested in Erlang. I think this is for a good reason: even if you don't like Erlang or you don't think it's a very good language for your needs, you probably would at least agree that Erlang is interesting.



Erlang is a strange creature. It's a functional, dynamically typed language with built-in concurrency semantics. It was created with a very specific purpose: to build large-scale fault-tolerant distributed systems. No other language, at least to my knowledge, has been designed so specifically to tackle this goal. Judging by the success of Ericsson's AXD301 switch and ejabberd, Erlang has delivered on its intended use.



Although it has commerical origins, Erlang is now open source, and it's making headway into the web development world. A language's web development capabilities seem to be one of the most attractive features for the larger developer community. How many people would become Ruby developers if it weren't for Rails? I don't think very many. Although Erlang isn't as far along as Ruby is in the web development department, I think it will close many of these gaps in the coming months. (I also think that the Erlang web stack will have a nice feature or two that will be very hard to build into Rails :) )



Today, I saw 4 Erlang-related articles on programmin.reddit.com: earlier this morning, my article OO, FP, Erlang, and Me was somewhere in the bottom half of the links. It may have been higher at some point -- I don't know. At number 2 (and it used to be at number 1) is Joe Armstrong's Why I Don't Like Shared Memory. At number 9) is Ask Reddit: is Erlang hype the next Ruby hype? I seriously don't think that Erlang's "hype" is anywhere close to Ruby's hype. Erlang's "hype" is basically my blog, wagerlabs.com and now Joe Armstrong's blog. I don't think we are trying to "hype" Erlang as much as raise awareness to the unique capabilities of this seriously under-hyped language, but other people may see it differently. At number 19) is David Bergman's Erlang: The Best or Worst of Two Worlds?. It may have something to do with my mentioning this article on my blog, but maybe it was discovered by the poster independently.



There's definitely a growing interest in Erlang, but until Erlang has a more complete web development stack and until one or two companies will have built a killer web app using Erlang, there will always be doubt about Erlang's true merits for pragmatic developers.



I think that many of these doubts will clear in the next few months.



By the way, saying that Erlang doesn't power any killer webapps is inaccurate: AFAIK, Meebo uses ejabberd for their instant messaging backend. If Meebo also used Yaws as their web server (I don't think they do, but I don't know for certain), they would probably have a simpler architecture.



I like simple :)

Interesting Take on Erlang by David Bergman

My friend and former collegue, David Bergman, has an interesting take on Erlang in his blog: Erlang: the Best or Worst of Two Worlds?



In this article, David discusses Erlang's mertis as a "practical" functional language for building large-scale systems. He also points out a couple of Erlang's aspects that he doesn't like: dynamic typing and lack of currying. Clearly, the first item is the more important.



I'm a big fan of dynamic typing, less from a theortical and more from a practical point of view. I think dynamic typing speeds up development because you can easly execute statements in the shell without previously defining your types. Without dynamic typing, I also don't think I could have created Smerl and ErlyDB -- at least not so easily. At the very least, they would have required the developer to define in compile time the "types" that would be generated in runtime. That's more effort than I would like to make as an ErlyDB user. Still, David brings up some very good points about static typing and I'm not sure that I disagree with him 100% :)



David is the smartest developer (among other things) I know personally and he's the main culprit behind getting me interested in functional languages. His blog is very good. I recommend it to everyone.

Monday, September 04, 2006

Goodbye, New York. Hello, Boston!

This past weekend, after a ~3 year tenure in Manhattan, NYC, I moved to Boston.



It was a crazy weekend that included endless shopping, moving boxes and furniture, painting walls, getting 2 parking tickets, and even attending my friend's wedding. (Guess where? In New York, of course! :) ).



I'm exhausted, but I made it.



Now I need to figure out my life out here.



Paul Graham thinks that nerds don't like New York. At least in my case, he's way off the mark. I love New York. I think it's one of the best cities on earth. No city is as exciting and fascinating as New York.



I will miss New York a lot.



Maybe Paul Graham is right: maybe I'm not a real nerd. Maybe all this Erlang stuff is just a facade, and deep down in my soul I really want to be a hip hop dancer or something :)



Nah... I really like coding. I enjoy this stuff. I sometimes work crazy hours just because I like it. When I don't work crazy hours, I often write code when I get home from work. Not always, though. I have a life outside of my MacBook.



So why Boston, of all places?



I didn't move here because I love Boston. I know Boston pretty well, and although I find it nice enough, I've never fallen in love with it. I definitely don't like it as much as I like New York.



The main reason I moved here is because my girlfriend of two years has been living here for a year now, and I wanted to live closer to her.



The second reason I moved to Boston is that wanted to be able to live cheaply for a while so I can live off my savings while I work on a fun project I want to build. I'm 26 years old, and I feel that this is a good time to do it. I don't have a lot of money, but I also don't have a wife, kids, college bills or mortgage payments. I don't even have a car (I'm from New York, remember? :) ). My savings will carry me for a few months. After that, maybe I'll have to find a real job or a consulting gig or something.



If that happens, I'll cross my fingers and hope that I can get a gig writing Erlang code.



I really enjoy working with Erlang much more than other languages for some reason. I don't even know if it's worth it anymore trying to come up with an objective-sounding list of justifications rather than just saying that I like how it feels.



Even if my project doesn't take wings, my investment in it will certainly bear fruit as I am planning on releasing all the framework-level code I write as open source. ErlyDB will see many improvements, but I will also probably release contributions to higher levels of the Erlang web development stack.



I hope that in a number of months, few people will question that Erlang is a great language for building cutting-edge web applications.



We'll see how all this plays out. I'll keep you posted on my progress.

Friday, September 01, 2006

OO, FP, Erlang, and Me


Drop the anti-OO rehtoric, it just makes you look stupid. For your information, objects are cheap to create in most languages. For example, .Net only need 12 bytes of overhead. Had you not starting attacking OO, I would have been more interested in what you have to say about Erlang and databases.



-- blog comment




I have gone through a string of languages before I seriously got into Erlang. I started learned programming in BASIC and Pascal in my early teens, and then I moved on to C/C++ in high-school. In college, most classes were taught in Java, although we had occasional excursions into C/C++, Scheme and Prolog. Professionaly, I have worked on web applications with Perl, PHP and Java. At my last gig, I have created a pretty large (for 1 developer, I would think) codebase in C: about 34,000 lines of code. I was a network application with a lot of threading and IO logic. It also interacted with a backend system written in Java.



I usually try to stay on top of the latest trends. When Ruby on Rails started getting a lot of buzz, it struck me as a nice alternative to the popular tools of the day, so I studied it pretty thoroughly and then I used it to make a prototype for a website. (I ended up dropping that prototype at the point when I realized I was hopelessly hooked on Erlang :) )



In my last gig, the Java backend code initially interacted with a database by making SQL calls directly via JDBC, but then we switched to Hibernate, 'The' Java ORM framework. After the switch, we saw a significant performance hit and actually considered switching back to JDBC. For several reasons, we eventually decided to take the performance hit and stick with Hibernate anyway.



Benchmarks often produce misleading results regarding the behavior of real system, so you should take the following with a grain of salt, but polepoes.org has ran some benchmarks comparing Java ORM frameworks to JDBC, and in their summary, they state, "The use of O-R mapping technology like Hibernate or JDO O-R mappers has a strong negative impact on performance. If you can't compensate by throwing hardware at your app, you may have to avoid O-R mappers, if performance is important to you."



I'm not an expert on Hibernate internals and I can't state precisely why it would add such an overhead, but, as I said, it most probably has to do with the heavyweight nature of objects. By 'heavyweight' I mean all not just the physical size of the object in memory, but the full context associated with the object. In OO languages that maintain runtime type information such as Java and C# (as opposed to C++) those 12 bytes of overhead that the commenter has mentioned hold a pointer to a class structure. That structure has lists of fields and methods, as well as pointers to its superclass and maybe also to the interfaces it implements. The same structure repeats iteself up the inheritance chain. ORM frameworks have to examine this complex structure, usually by reflection, in order to figure out how to map instance variables to database fields.



(Hibernate actually performs bytecode instrumentation to lower the overhead associated with reflection. I'm not sure what the speed gains are, though. Regardless, we did notice that Hibernate adds overhead to performance.)



In dynamic OO languages such as Ruby, objects have an even higher overhead than in Java and C# because every object has its own hash table that holds its methods, and each method call requires a hash table lookup. That's (partly) why Ruby is slower than Java and C#.



By the way, I'm not trying to suggest that ORM is "bad" or that Hibernate is a bad product. If I used an OO language to build a web application, I would probably use an ORM framework. If I used Java, I would probably use Hibernate because it's mature and feature-rich. Developer productivity is generally much more valuable than the cost of buying a few extra servers.



Back to my programming history: although I have tasted some functional programming in college, it has been in an academic setting. In the "real-world," I have rarely heard of companies using functional languages. Mainstream programming-related websites such as oreillynet.com and devx.com hardly ever talk about any functional languages. Try to search for a Lisp, Haskell or Erlang job on craigslist or monster.com and you'll likely get zero results. All this gave me the impression that functional languages are more for academics than for people who build real systems.



The general story I and many other programmers of my generation have been told is as follows (I'm simplifying, of course): at first there was C, then C++ came and made C better by adding object orientation. Then Java came and made programmers lives much better by adding garbage collection, single inheritence and platform independence.



We also learned that the LAMP stack and with its various scripting languages is an alternative for developers who want to get things done cheap and also quick-and dirty.



When I first discovered Erlang, I wasn't thrilled. "Why bother with some obscure language designed for the telcom industry? Nobody probably uses it besides Ericsson and that jabber server -- ejabberd -- so why should I? Anyway, I already have Java, which makes my life easy," I thought. The look of the website -- especially the documentation area -- didn't add to my enthusiasm, either. It felt too old-school.



However, as much as I initially disliked it, Erlang kept pulling me back. The fact that it was designed for building distributed systems was too alluring. I've done my part in building such systems in C and Java and I know how hard it is. Race conditions, deadlocks, RPC protocols, nodes crashing, monitoring difficulties, logging, resource leaks, obscure bugs, etc, are all major pains in the neck. They are much worse when you're using languages that weren't designed to address those issues.



I have suffered the pains, and I wanted to find a better way.



That's why I kept on gravitating back to the Erlang documentation site, doing the tutorials, experimenting, reading code, asking questions and educating myself. The more I learned about Erlang, the less I missed the Java/C/C++ ways of doing things. After a while, I realized what a great language it was. Everything just fit together perfectly -- message passing, distributed programming, faul-tolerance, high-availability, pattern matching, dynamic typing, rapid development, functional semantics, a distributed database...



When I finally felt that I 'got' Erlang, never once did I miss a single OO construct. In fact, I started regarding OO as a burden. In OO languages, every class, every method, every field has so much context around it. To understand where piece of code fits into the big picture, you have to read through the documentation for all the classes and interfaces to which it belongs. Also, OO languages often encourage if not force you to wedge your types into some inhertiance chain in order to reuse code, which results in ugly inhertiance relations that are inflexible at best.



Functional languages like Erlang have the opposite philosophy. They try to minimize the context surrounding a piece of logic-- a function. All you have to know is what parameters a function takes and what it returns. There is no implicit link between the function and the data it uses. With single-assignment, you don't even have to worry about functions mangling the values of your variables. When you're coding in Erlang as opposed to Java, you think less about the context of your functions and more about what they do and how to compose them together to solve your problem.



That's what a good programming language is about: it should let you express the solution to your problem as concisely and easily as possible so you can move on to the next problem. It should also make it easy to compose multiple components into a larger whole.



When the Erlang lightbulb went off in my head, I actually started feeling some resentment towards the rest of the software world, which is dominated by OO thinking. "Why didn't anybody tell me about this earlier? Why isn't Erlang featured in the mainstream software press? Why is Ruby on Rails on Oreilly's radar but Erlang isn't? Why is everybody chasing OO features while overlooking this great language? Why did I spend so much time working with much worse languages? Erlang is twenty years old. It has been open sourced in 1998. How could the software community ignore it so thoroughly?"



This is partly I occasionally take jabs at the OO world. Part of me feels that it has mislead me and kept me away from a beautiful tool that would have made my life much better had I known about it sooner.

And much more fun :)

Wednesday, August 30, 2006

Many-to-Many Relations Are Now at an ErlyDB Near You

The title says it all :)



Not only that, I also added more powerful SELECT query capabilities to many-to-one relations.



Here's how it works:



Add these tables to erlydb.sql



create table developer(
id integer auto_increment primary key,
name varchar(30),
country varchar(20));

create table developer_project(
developer_id integer,
project_id integer,
primary key(developer_id, project_id));


This is our modified project.erl file:



-module(project).
-compile(export_all).

relations() ->
[{many_to_one, [language]},
{many_to_many, [developer]}].


This is our new developer.erl files:



-module(developer).
-export([relations/0]).

relations() ->
[{many_to_many, [project]}].


Following is some code demonstrating the new capabilities. The full module is in the distribution, in test/erlydb_test.erl.



%% fancier project queries
{ok, [Yaws4]} = language:projects_where(
Erlang, "name='Yaws'"),
true = Yaws4 == Yaws1,

{ok, [Yaws5]} = language:projects_with(
Erlang, "limit 1"),
true = Yaws4 == Yaws5,

{ok, [Ejabberd4]} = language:projects(
Erlang, "name like '%e%'", "limit 1"),
true = Ejabberd4 == Ejabberd3,


%% Let's show off some many-to-many features

%% First, add some more projects
[OTP, Mnesia] =
lists:map(
fun(Proj) ->
{ok, P1} = project:save(Proj),
P1
end,
[project:new("OTP", "The Open Telephony Platform", Erlang),
project:new("Mnesia", "A distributed database " ++
"engine written in Erlang", Erlang)]),

%% Next, add some developers
[Joe, Ulf, Klacke] =
lists:map(
fun(Developer) ->
{ok, D1} =
developer:save(Developer),
D1
end,
[developer:new("Joe Armstrong", "Sweden"),
developer:new("Ulf Wiger", "Sweden"),
developer:new("Claes (Klacke) Wikstrom", "Sweden")]),

%% Add some developers to our projects
ok = project:add_developer(OTP, Joe),
ok = project:add_developer(OTP, Klacke),
ok = project:add_developer(OTP, Ulf),

%% Add some projects to our developers
ok = developer:add_project(Klacke, Yaws1),
ok = developer:add_project(Klacke, Mnesia),
ok = developer:add_project(Ulf, Mnesia),


%% basic SELECT query
{ok, [Joe, Ulf, Klacke]} =
project:developers(OTP),

%% fancier SELECT queries
{ok, [Ulf, Klacke]} =
project:developers(Mnesia),
{ok, [Ulf]} = project:developers_with(Mnesia,
"limit 1"),
{ok, [Klacke]} =
project:developers_where(Mnesia,
"name like 'Claes%'"),

%% SELECT query, from the other direction
{ok, [Yaws1, OTP, Mnesia]} =
developer:projects(Klacke),

%% Klacke, nothing personal here :)
ok = developer:remove_project(Klacke, Yaws1),
{ok, [OTP, Mnesia]} = developer:projects(Klacke),
ok = developer:remove_project(Klacke, OTP),
{ok, [Mnesia]} = developer:projects(Klacke),
ok = developer:remove_project(Klacke, Mnesia),
{ok, []} = developer:projects(Klacke),

%% I forgot to show you can delete records, too :)
ok = language:delete(Java).


ErlyDB is still in alpha version, so you may have problems. Please let me know if you find any bugs :)



(FYI, I'm moving to Boston tomorrow, so I will probably not be of much help in the next few days.)



Enjoy!

Tuesday, August 29, 2006

Introducing ErlyDB: The Erlang Twist on Database Abstraction

Every web developer craves a database abstraction layer. Ruby, PHP, Java and Python all have them. Many developers have adopted web frameworks just for their database abstraction capabilities. The lack of such a framework has even caused some developers to hesitate before using the best language of them all for building world-class backends: Erlang.



That's why I created ErlyDB: The Erlang Twist on Database Abstraction :)



ErlyDB isn't a database abstraction layer, but a database abstraction layer generator. ErlyDB taps into Erlang's runtime metaprogramming powers to generate an abstraction layer for your database on the fly. This layer is as flexible as it is paper-thin.



Unlike ORM frameworks, ErlyDB works directly with Erlang tuples, which are simple immutable arrays that map very easily to database records. This incurs less overhead than object-relational mapping solutions, which rely on more heavyheight objects to represent database rows.



With ErlyDB, productivity doesn't come at the expense of performance :)



ErlyDB is in an alpha stage right now. It only supports MySQL; it hasn't been thoroughly tested and optimized; and it's not feature-complete by any means. However, I'll be adding many more features and improvements over time. If you strongly need a feature before I implement it, I encourage you to implement it yourself and share it with the rest of us. I will be accepting any useful, high quality contributions from other developers.



Let's do a short tutorial.




  • Get ErlyDB from the subversion repository and install it in your code path (on my Mac, it's /usr/local/lib/erlang/lib).
  • Get the MySQL driver from process-one.net and install it in your code path.
  • Create a MySQL database called 'test'

  • Run the following SQL script:



create table language (
id integer auto_increment primary key,
name varchar(50),
paradigm varchar(30),
creation_year integer);

create table project (
id integer auto_increment primary key,
name varchar(50),
description varchar(50),
language_id integer,
index(language_id));


  • Create the file "language.erl" with the follwing code and compile it in your code path:




-module(language).
-export([relations/0]).

relations() ->
[{one_to_many, [project]}].


  • Create the file "project.erl" with the following code and compile it in your code path:





-module(project).
-export([relations/0]).

relations() ->
[{many_to_one, [language]}].


  • Implement the following module, which illustrates some of the common idioms of ErlyDB.






-module(erlydb_test).
-export(
[init/0,
test/0]).

init() ->
%% connect to the database
erlydb:connect(mysql, "localhost", "username", "password",
"test"),

%% generate the abstraction layer modules
erlydb:code_gen([language, project]).

test() ->
init(),


%% clean up old records
erlydb:q("delete from language;"),
erlydb:q("delete from project;"),

%% Create some new records
Languages =
[language:new("Erlang",
"A fun and productive functional language with " ++
"top-notch concurrency features designed for "++
"building scalable, fault-tolerant systems. " ++
"Erlang is an excellent choice for building "++
"anything from websites like hamsterster.com " ++
"to commercial phone switches.",
"functional/dynamic/concurrent", 1981),
language:new("Java",
"An OO language designed to make the lives of " ++
"C++ programmers less painful.",
"OO/static", 1992),
language:new("Ruby",
"An OO language designed to make the lives of " ++
"Java and Perl programmers less painful.",
"OO/script/dynamic", 1995)],

%% Save the records in the database and collect the updated
%% tuples.
[Erlang, Java, Ruby] =
lists:map(
fun(Language) ->
%% executes an INSERT statement
{ok, Lang} = language:save(Language),
Lang
end, Languages),

%% demonstrate getters
"Erlang" = language:name(Erlang),
"functional/dynamic/concurrent" =
language:paradigm(Erlang),
1981 = language:creation_year(Erlang),

%% demonstrate setter
J1 = language:creation_year(Java, 1993),

%% executes an UPDATE statement
{ok, J2} = language:save(J1),

1993 = language:creation_year(J2),


%% Lets run some queries
{ok, E1} = language:find_id(language:id(Erlang)),
true = E1 == Erlang,

{ok, [E2]} = language:find_where("name = 'Erlang'"),
true = E2 == Erlang,

{ok, [E3]} = language:find(
"WHERE paradigm = 'functional/dynamic/concurrent' " ++
"LIMIT 1"),
true = E3 == Erlang,
{ok, [E4, J4, R4]} = language:find_all(),
true =
E4 == Erlang andalso
J4 == J1 andalso
R4 == Ruby,

%% Let's make some projects

Yaws = project:new(
"Yaws", "A beautiful web server written in Erlang",
Erlang),
Ejabberd = project:new("ejabberd",
"The best Jabber server, hands down", Ruby),
OpenPoker =
project:new("OpenPoker",
"A scalable, fault-tolerant poker server", Erlang),


%% We call language:id just to demonstrate that constructors
%% accept both related tuples or, alternatively, their id's.
%% This example would behave identically if we used the
%% Java variable directly.
Tomact =
project:new("Tomcat",
"A Java Server with XML config files",
language:id(Java)),

JBoss =
project:new("JBoss",
"A Java Application Server with more XML files",
Java),
Spring =
project:new("Spring Framework",
"A Java IoC framework oozing XML love", Java),


Mongrel =
project:new("Mongerl",
"A web server with a funny name", Ruby),
Rails =
project:new("Ruby on Rails",
"A nice integrated web framework for building " ++
"CRUD websites.", Ruby),
Ferret = project:new("Ferret",
"A Ruby port of Apache Lucene. It would be nice " ++
"if someone ported it to Erlang", Ruby),
Gruff = project:new("Gruff",
"A Ruby library for easy graph generation. " ++
"An Erlang implementation would be nice as well",
Ruby),

Projects = [Yaws, Ejabberd, OpenPoker, Tomact, JBoss,
Spring, Mongrel, Rails, Ferret, Gruff],

%% Insert our projects into the database
[Yaws1, Ejabberd1, OpenPoker1 | _Rest] =
lists:map(
fun(Project) ->
{ok, P1} = project:save(Project),
P1
end, Projects),

%% let's get the language associated with Yaws
{ok, Erlang2} = project:language(Yaws1),
true = (Erlang2 == Erlang),

%% now let's correct a grave error
{ok, Ejabberd2} = project:save(
project:language(Ejabberd1, Erlang)
),
true = language:id(Erlang) ==
project:language_id(Ejabberd2),


%% let's get all the projects for a language
{ok, [Yaws3, Ejabberd3, OpenPoker3]} =
language:projects(Erlang),
true =
Yaws3 == Yaws1
andalso Ejabberd3 == Ejabberd2
andalso OpenPoker3 == OpenPoker1,

ok.

(This code is included in the 'test' directory of the ErlyDB distribution.)




  • Read the code and experiment.




As you've probably guessed, ErlyDB uses Smerl to do its magic. (Confession: when I created Smerl, ErlyDB was just what I had in mind :) ) ErlyDB takes advantage of all of Smerl's advanced features, such as metacurrying, parameter embedding and module extension. You may find it interesting to look at the code and see how ErlyDB works under the hood.



Adhering to the Erlang philosophy of zero downtime, the ErlyDB abstraction layer can change in runtime without taking the system offline. Simply call erlydb:code_gen with the module names to regenerate and everything will work as expected.



Please get your hands on ErlyDB and give it a test drive. Let me know if you find any bugs or if you have any suggestions.



Coming very soon:



  • Many-to-many relations

  • Transactions

  • Event handlers (before_save, after_save, etc.)



Coming soon:



  • Prepared statements

  • Support for additional database engines (probably when edbc comes out, unless other people make temporary drivers beforehand.)

  • Better connection pooling (also probably tied to edbc)

  • Real documentation :)

  • Performance optimizations

  • More customizations

  • Fine-grained control on field visibility

  • Multiple models per table

  • More versatile SQL query generation

  • Support for complex queries

  • and more



Enjoy!





Appendix



Erlang users have actually had a nice alternative to database abstraction: Mnesia. Mnesia is an industrial-strength, distributed database engine written in pure Erlang. Although Mnesia is quite beautiful, it isn't the best fit for all applications. Mnesia's biggest drawback (at least as I see it) is that Mnesia isn't designed to scale to very large (many gigs) data volumes. I'm hoping the OTP team will improve this aspect of Mnesia, but until it does, we have to live with this limitation.



Even if Mnesia didn't have this shortcoming, many developers would still prefer to use other database engines for their various capabilities. MySQL, Postgres and Oracle aren't going away any time soon.



Having said that, Mnesia can very useful even if you're using another database engine. For instance, a killer application for Mnesia is a distributed session store shared between instances of a Yaws cluster. Mnesia could also be used as a distributed cache for recently-accessed database records.



Update: I just realized that there's no reason ErlyDB shouldn't have a Mnesia driver. Any takers? :)

Smerl Updates

2 Quick updates:




  • I made source discovery in Smerl more robust by using the module_info function.

  • I changed the Smerl license from the BSD to the MIT license.

Sunday, August 27, 2006

Museum of Natural History

Dear readers,



I'd like to take a short break from my Erlang postings and share a few pictures I took on my trip earlier today to the Museum of Natural History in New York.



Note: I did some retouching with GIMP (actually, GimpShop for OS X) to enhance the dynamic range of these images, as the originals suffered from faded colors due to the poor lighting conditions.



A Velociraptor


IMG_1433.JPG



A green lizard


IMG_1507.JPG



This dino must have been coding in Java. Its neck looks like this stack trace :)


IMG_1447.JPG



A chameleon


IMG_1515.JPG



You can view the rest of the set here

To Web Developers: Think Outside The Thread

A few people have asked me this very good question (I'm paraphrasing): "If I'm just trying to build a webapp, and I don't need telcom-grade scalability, why should I use Erlang? Yes, Erlang may be the best language for concurrent programming, but I will never have to use Erlang's concurrency features directly, just as I don't use any threading libraries when I'm building a webapp with other languages."



Here's my answer: you can certainly build a webapp without using concurrency features directly. Most web developers don't. Just keep in mind that most framework designers use languages that support concurrency so poorly, that they have resorted to fooling you into thinking that the only webapps you can realistically build must follow the good ol' request-response, single-threaded, CRUD-based paradigm.



This is clearly a fallacy.



Many high-quality, innovative webapps don't follow this paradigm.



The Google search engine doesn't follow this paradigm. Neither does Meebo.



Many of the great webapps of tomorrow won't follow this paradigm.



Why should your webapp follow this paradigm?



The paradigm is shifting to a large degree because of one main innovation, which somebody has named "Comet" (it's a silly name if you ask me, but it has stuck). Comet boils down to having the browser keep an open XMLHttpRequest connection to the server, waiting for the server to send it messages. This opens the door to full bidirectional communication between the browser and the server (this is essentially what Meebo does).



If you want to build a Comet app with today's Java, Ruby or Python frameworks -- good luck. Not only will the message-passing -- not to mention clustering -- logic be painful to code (especially if you've tasted the power of Erlang :) ), your servers will also croak when your app reaches a few thousand (or fewer) simultaneous users.



Partly for these reasons, nobody uses Ruby or Python to build commercial phone switches (not that I know of, anyway :) ). However, Ericsson builds them quite successfully with Erlang. Erlang powers highly scalable, fault-tolerant phone switches with nine nines availability. Building scalable clusters is what Erlang is made for, and I dare say Erlang makes such programming tasks (relatively) easy.



If you want to build an app that uses Comet, you will need concurrency and scalability, so use Erlang.



However, if your app doesn't use Comet, should you still care about Erlang's unmatched capabilities for concurrency, clustering and message passing?



Yes.



Another good reason to use Erlang is that your web application may benefit from -- or even require, as in Google's case -- distributing a calculation over multiple processors or even multiple nodes in a cluster prior to sending a response back to the browser.



Erlang is designed for distributed programming. In Erlang, sending a message to a remote node is as easy as sending it to another process in the same box. As Joe Armstrong has shown, writing a parallel version of lists:map is almost laughably easy in Erlang. This is all it takes:




pmap(F, L) ->
S = self(),
Pids = map(fun(I) ->
spawn(fun() -> do_f(S, F, I) end)
end, L),
gather(Pids).

gather([H|T]) ->
receive
{H, Ret} -> [Ret|gather(T)]
end;
gather([]) ->
[].

do_f(Parent, F, I) ->
Parent ! {self(), (catch F(I))}.


Distributed computation will grow in importance as server manufacturers race to add more cores to their boxes. (The next release of Sun Niagara will have 64 cores, for instance.) Even if you don't need distributed computation right now, you'll benefit from adding Erlang to your toolbox. Multi-core computation is where things are going, and knowing Erlang will help you stay on top of the game.



By the way, I'm not suggesting that Erlang has a monopoly on distributed programming -- Erlang is just years ahead of any other language in this area. Erlang has 20 years of development behind it for this specific purpose, with a long track record of success in large-scale production systems. Sure, you always have the option of using, say, Starfish for Ruby. You'd just have to cross your fingers and hope your competition doesn't use Erlang :)



To summarize, if you are 100% confident that you will never attempt to push the envelope of what your webapp's backend can do, you probably won't need Erlang's concurrency features. IMO, you'll have fun by using Erlang, but you certainly don't need it. However, if you start venturing into areas that are beyond the single-threaded CRUD view of the world, Erlang's capabilities will help you greatly.



So why use Erlang?



Think outside the thread.

Friday, August 25, 2006

Who's Going To The Erlang Workshop?

Hi,



I'm curious as to who's planning on going to the Fifth ACM SIGPLAN Erlang Workshop in Portlang on the 16th (the link is on the front page of http://erlang.org).



I haven't made up my mind yet if I should go. It would be fun to meet some Erlangers face to face but I have no idea how popular this workshop is.



I'd appreciate it if somebody could clue me in.



Thanks in advance!

Thursday, August 24, 2006

New Traffic Records

The picture says it all.






This is weird.



When I started blogging about Erlang, I enjoyed being in a small niche of bloggers that write about "exotic" languages. I've never thought my blog would get all this attention. Sometimes, I don't like all this attention :) However, you don't always get in life what you've expected, so I'll do my best to enjoy the ride.



Erlang is just getting started. Erlang will make huge strides into the web development world. We will build frameworks that make Erlang developer's lives easy, if not easier, than those of Ruby on Rails developers. Ruby on Rails didn't exist two years ago, and Erlang (with Yaws) is years ahead of where Ruby was when Rails was born. In a matter of months, Erlang will be a serious contender in the web development world -- not just for developers who want insane scalability with 3 milliseconds downtime per year -- but also for developers who just want to get things done.



Real-time interactivity on the web is a relatively unexploited land full of opportunities for adventerous developers. These days, building real-time interactive applications with Comet technology in any language but Erlang just makes no sense. Erlang has 20 years of development behind it with the specific design goal of building scalable servers. No other language comes close. It also makes development fun.



As Joe Armstrong has said, Erlangers have a head start.



Libraries are coming.

Ericsson's Biggest PR Blunder: Forgetting to Tell Us That Erlang Programming Is FUN

As you may have noticed, Ericsson hasn't done the best PR for Erlang. The closest things resembling sales pitches I see from that part of the world are either academic-looking papers or PowerPoint presentations that require downloading heavy PDF files. There are also the mailing list postings that are often intelligent and hilarious but they are ultimately preaching to the choir.



When people talk about Erlang, they usually mention how Erlang is great for building concurrent, distributed, highly-available, fault-tolerant, systems; it powers phone switches with nine nines availability; the AXD 301 switch has 850K lines of Erlang code; Yaws scales with large numbers of connections; ejabberd is the most scalable XMPP server; and all sorts of such heavy-sounding accomplishments.



If I hadn't read Joel Reymont's wagerlabs.com blog, where he wrote about his experiences writing a poker server in Erlang, I probably would have never thought I would actually like Erlang as a language.



What nobody from Ericsson talks about is that Erlang makes coding FUN.



It may be possible to arrive at this realization through deduction: to build large-scale, stable systems you need a productive language. If the language got in your way and prevented you from doing things in a straightforward manner, your code would start growing in complexity. Complexity leads to bugs. Bugs lead to downtime. Systems written in Erlang must have close to zero downtime. Therefore, Erlang must make developer's lives easy.



For developers, ease often equates with fun. Ease means that they can express their thoughts succinctly, test their solutions quickly, and then move on to the next problem.



Programmers love garbage collection, for instance, because it makes their lives easy. Similarly, some programmers are Ruby fanatics because they think Ruby is the epitome of ease (I used to think so too in the old days -- about 3 months ago :) ). Other programmers believe ease comes from using functional languages, because they are the most powerful.



You can read Paul Graham's essays on Lisp about this. You can also read Peter Norvig's comparison between Python and Lisp. (As you're reading this comparison, mentally add Erlang as well as 2 more categories: concurrency and fault tolerance, and picture Erlang as being the top dog :) )



So what exactly makes Erlang coding fun? To me, these are the main factors:




  • Erlang is a functional language. It fits well in my brain.

  • Erlang is dynamically typed, which means that I can write less code (read Haskell vs. Erlang, Reloaded) and also test my code easily in the Erlang shell. (Erlang's dynamic nature also allowed me to create Smerl :) )

  • Erlang has pattern matching, which lets me write a single line of code to express a thought that would in other languages translate into a horrendous structure of nested if-else statements.

  • Erlang has single-assignment semantics, which means that functions have no side effects (on bound variables). This makes Erlang code very readable. It also makes debugging easy.

  • Concurrency, concurrency, concurrency.

  • With Erlang's hot code swapping, I can deploy my changes unto a system while it's running. When I made the haXe remoting adapter for Yaws, I didn't have to take Yaws offline (try that with Apache or Lighttpd :) ).

  • The compiler checks the validity of my code without locking me into a type system.

  • Good runtime metaprogramming capabilities (with Smerl).

  • I used to like Eclipse, but Erlang made me an Emacs fiend :)

  • I'm learning a lot and interacting with very smart people.



Some people have asked me, "If all I want is to build a stateless, CRUD-style webapp, and I don't need telcom-grade scalability, etc, why should I bother learning Erlang? Ruby on Rails handles it just fine. It also has more web development libraries."



I hope I was able to give a reasonable answer to this question. However, as much as I write about Erlang, reading this blog won't take you all the way there. You have to experiment with Erlang and see how it feels for yourself. I can't guarantee you'll like it -- all I can do is tell you why I do.

I Can Feel It in the Ether: A Big Erlang Renaissance Is Coming

A few weeks ago, I submitted to digg.com an article I had written comparing web development with Erlang + Yaws to Ruby on Rails. Why? Because it seemed like Ruby on Rails was getting all the buzz, whereas the developer community was overlooking an arguably much more powerful alternative: Erlang + Yaws.



By "more powerful," I don't mean to suggest that Yaws has more web development libraries or that it's as accessible to most web developers as Ruby on Rails.



It isn't.



(Yaws does have many useful APIs -- just not as many as Rails).



I mean "powerful" in the sense that Ericsson has been developing Erlang for 20 years with the goal of creating the ultimate language for powering its distributed, fault-tolerant, massively scalable telephone switches -- the stuff that operates with %99.9999999 (nine nines) availability.



Erlang has delivered.



Yaws is a web server written in pure Erlang, which means that it automatically inhertis the traits that have made Erlang-powered telcom switches so robust. When you're building a webapp with Yaws, you have the full power of Erlang at your fingertips.



The cost? $0.



The source code? Open.



All this stuff struck me as a very appealing package, especially in contrast to the popular array of web development tools (last I checked, nobody was programming commercial phone switches in Python or Ruby :) ) but despite my semi-serious attempt to promote it, my article got only 18 diggs.



Possibly overreacting, I thought that my Digg experience has proven that the larger developer community will probably never be interested in Erlang.



"It's a functional language in a Java dominated world," was my favorite rationalization.



Apparently, I made a mistake by thinking of digg as "the" destination for serious developers. A couple of weeks ago, somebody submitted my Erlang + Yaws vs. Ruby on Rails article was to reddit.com, where it made the front page. Then another article I wrote, Why Erlang Is a Great Language for Concurrent Programming was featured on reddit.com as well.



"Wow," I thought, "it looks like reddit.com is where less mainstream but more interesting programming blogs get real attention."



After these events, I started following reddit.com -- especially programming.reddit.com. I was mostly curious as to what kind of programming languages are featured there.



Today, I had a very pleasant -- almost shocking -- surprise: programming.reddit.com has 6 Erlang-related links, the top of which is also on the front page of reddit.com.



Here they are:



  • 1) New Blog: Joe Armstrong (one of the fathers of Erlang) (armstrongonsoftware.blogspot.com).

  • 3) Secret Weapons for Startups (yarivsblog.com)

  • 5) The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software (gotw.ca)

  • 9) Haskell vs. Erlang (wagerlabs.com)

  • 19) HiPE (High Performance Erlang compiler) presentation (erlang.se).

  • 22) The DIALYZER: a DIscrepancy AnaLYZer for ERlang programs (eg, an Erlang debugger) (ii.uu.se)



This is nothing short of amazing. I've never seen so many links specific to one language on programming.reddit.com -- and Erlang is far from one would call "popular."



Maybe I'm just seeing trends where I'm subconsciously trying to look for them, but maybe this really does indicate real shifts are happening and that developers are starting to recognize that for building scalable, high-available, fault tolerant systems, today's array of popular programming languages are simply nowhere close to where Erlang was 20 years ago.



Interesting times are ahead for Erlang.




Side note: DIALYZER isn't a debugger, but a static analysis tool for finding software defects.

Wednesday, August 23, 2006

New Erlang Blog by Joe Armstrong

There's big news in the Erlang blogsphere.



Today, Joe Armstrong, one of Erlang's original creators ("The" creator of Erlang?), started a new blog in which he'll write about the events and people that have shaped Erlang's history, as well as the stories that will shape its future.



This is very exciting. Until today, the most comprehesive source for Erlang history I've read has been Joe's PhD thesis. However, as you might expect, although this paper is very rich in technical material, it doesn't dwell too much on the human side. Now, we'll be able to know more about the Erlang story from the perspective of a true insider.



Judging by the substance and humor of Joe's mailing list postings, which I sometimes quote on this blog, I'd bet that Joe's blog will be a great read.



I hope more people follow in Joe's footsteps and start blogging about Erlang. Many people on the Erlang mailing list are far more knowledgable about Erlang -- and other programming languages (well, maybe except for Ruby and haXe :) ) -- than I am. Many of them are also great writers. If they started blogging, it would make the Erlang blogsphere much richer.



I get much of my knowledge about Erlang from reading mailing list postings, but this kind of knowledge isn't very accessible to non-Erlangers. Blogging is a better tool for spreading the word to the outside world. Blogs also can be less technical and more open-ended than mailing list postings, in which one follows a stricter etiquette in trying to stick to the point and not waste too much of people's time. A blog, on the other hand, is what you make of it. If a blog is good, people discover it and its importance grows. If a blog sucks, at least people have the option of ignoring it :)



The best part of Joe's announcement, at least for me, is that he credited me with inspiring him to start blogging. Reading these words made me feel very honored.




Yariv's blog http://yarivsblog.com/ with his frequent Erlang postings
has inspired me.



I think he needs a little competition :-)



So I've started writing ...



In this blog I'll try to tell you some of the things that are happening in the Erlang world. A lot of stuff is happening behind the scenes, I'll try to tell you about some of this.



The first post is:



http://armstrongonsoftware.blogspot.com/2006/08/making-money-from-erlang.html



Cheers



/Joe




When I stared this blog, I really didn't have very high expectations, so it's thrilling to see this blog make a real impact on the Erlang world. (I hope that the world outside has taken notice as well :) )



Getting credit is great, but giving it is even better: it was Joel Reymont's wagerlabs.com blog which has turned a mild curiousity about Erlang into a strong interest for me and also inspired me to start blogging about Erlang.




Oh, I almost forgot to mention -- Joe will also blog about cats. I must not forget the cats! :)



Happy RSSing! :)

A Couple of Smerl Updates

I added a few new features to Smerl earlier today.




  • smerl:extend/2 now injects the parent/0 function, which returns the parent module's name, into the child module. This allows explicitly calling parent functions from the child module. (Using smerl:for_module/1, the child can also mutate its own parent in runtime, which puts an interesting twist on family relationships :-) )
  • smerl:to_src/1 returns the pretty-printed source code for the MetaMod object.

  • smerl:to_src/2 writes the pretty-printed source code for the MetaMod object into a file.



Enjoy!

Tuesday, August 22, 2006

New: Module Extension in Erlang with Smerl

Have you ever wished you could easily add all exports from a "parent" module to a "child" module in the form of remote function calls to the parent, without overwriting the child module's exported functions?



If you have, today is your lucky day! With Smerl, you can now do it in a single line of code by calling smerl:extend/2 :)



I know words like 'extension' and 'inheritance' are generatlly shunned in the functional programming world, and for a good reason: in OO languages, these concepts have caused endless complexity, crufty code and bug-ridden horrors.



However, I should stress that the Smerl extension mechanism doesn't violate any functional programming tenets. Smerl's extend/2 is basically a smart function generator. It does not allow you to extend data fields in any way, nor does it create any artifical bindings between data and code.



(I believe Haskell has a similar, statically typed approach to module inheritance, but I only have rudimentary knowledge of Haskell so I may be wrong on that one.)



Here's a quick example:



P1 = smerl:new(parent),
{ok, P2} = smerl:add_func(P1, "add(A, B) -> A+B."),

%% 'false' indicates to not export the function
{ok, P3} = smerl:add_func(P2, "subtract(A, B) -> A-B.", false),

{ok, P4} = smerl:add_func(P3, "multiply(A,B) -> A*B."),
smerl:compile(P4),

C1 = smerl:new(child),
{ok, C2} = smerl:add_func(C1,
"multiply(A,B) -> throw(not_allowed)."),

C3 = smerl:extend(P4, C2),
smerl:compile(C3),

8 = parent:add(3,5),
{'EXIT', {undef, _}} = begin catch parent:subtract(4,3) end,
6 = parent:multiply(3, 2),
11 = child:add(2,9),
not_allowed = begin catch child:multiply(5,3) end,
{'EXIT', {undef, _}} = begin catch child:subtract(4,2) end.


Seems exotic? Maybe. However, I think this feature is very powerful. I have actually seriously needed this feature in my own project. If you have needed it too, I hope I just made your life a bit easier :)



Please let me know if you have any problems or suggestions.



Enjoy.



Update (8/23/06): The extend/2 function now also embeds the parent/0 function in the child module. parent/0 returns an atom with the name of the parent's module. This allows child functions to explicitly invoke parent functions (among other things).

New Smerl Capability: Embedding Values in Place of Arbitrary Function Parameters

I added a couple of new functions to Smerl to make Erlang metaprogramming with Smerl even more powerful. They provide a capability similar to metacurrying, but more flexible.



smerl:embed_params/2 takes a function form and a list of {Name, Value} pairs. For all clauses of the function, it iterates through their parameters, replacing each parameter that matches an item in the list with a variable in the body of the function that is bound to the item's value.



Reading the above sentence may feel like getting hit by a truck, so let's take a look at an example:




M1 = smerl:new(foo),
{ok, M2} = smerl:add_func(M1, "bar(A,B,C) ->
io:format(\"~s ~s ~s\", [A,B,C])."),
{ok, F1} = smerl:get_func(M2, bar, 3),
F2 = smerl:embed_params(F1, [{'A', "Lucy"}, {'C', "Sky"}]),
{ok, M3} = smerl:add_func(M2, F2),
smerl:compile(M3),
foo:bar("in the"). %% outputs "Lucy in the Sky"


The other function I added is smerl:embed_all/2. This function takes a MetaMod object (the thing you get back when calling smerl:new/1, smerl:for_module/1, or smerl:for_file/1), and applies smerl:embed_params/2 to all functions in the module. Sounds bizzare? It may be, but I have found it useful in a project I got cooking :)



Enjoy!

Sunday, August 20, 2006

Smerl Has A New Home

Smerl started as an rough idea, then became an experiment, and now it has grown into pretty powerful library. I think Smerl only scratches the surface of what one can do with Erlang metaprogramming, but I want to keep Smerl simple ('Smerl' is, after all, an acronym for Simple Metaprogramming for Erlang), so I'm not planning on adding many feature to Smerl at the moment.



(I will implement fixes and tweaks to make Smerl's current features easier to use but I'm not planning on adding new features unless they have a compelling value, e.g. metacurrying.)



To make it easier for others to follow Smerl's evolution (and to contribute to Smerl, if they wish ;) ), I have decided to move Smerl to code.google.com, where it will live in a subversion repository and enjoy other amenities for "real" projects, such as an issue tracking system.



Without further ado, here's Smerl's new home: http://code.google.com/p/smerl/.



I will keep blogging about Smerl. To see only Smerl-related articles, you can visit http://yarivsblog.com/tag/smerl (which also has a corresponding RSS/Atom feed).

Saturday, August 19, 2006

Erlang Metaprogramming Breakthrough: Metacurrying!

Quick download: smerl.erl

This is pretty big.



As I've been hacking away with Smerl last night, I had the following realization: in most cases, the form for a metafunction is mostly known in compile-time, and it only requires a small injection of runtime data to attain its final form.



This is conceptually very similar to currying.



Once these thoughts have fully materialized in my mind, I again sat down by my MacBook and frantically hacked into Smerl the very capability of runtime metacurrying!



What is metacurrying? In regular currying, you bind a value to a function's parameter(s), which gives you a new, simpler, function. In metacurrying, you bind a value to a function form, which gives you a new, simpler, function form!



This is a huge step forward for Smerl. Why? Because it finally frees the programmer from having to know the Erlang abstract format. With metacurrying, Erlang programmers finally get full compile-time checking for their metafunctions, which finally truly blurs the line between compile-time and runtime metaprogramming in Erlang.



I added a few new functions to Smerl:




  • smerl:curry/2 takes a function's abstract form and a parameter value (or list of paramter values) and returns the new, curried form. This is great for debugging and understanding what happens behind the scenes in metacurrying.

  • smerl:curry/4 takes a MetaCtx object or a module name, a function name, arity and parameter value (or list of parameter values) and returns the curried for for the function. This is essentially a smerl:get_func followed by a smerl:curry/2.
  • smerl:curry_replace/3 takes a MetaCtx object, a function form and a parameter value (or list of parameter values) and replaces the old function with the function's curried form

  • smerl:curry_replace/4 takes a MetaCtx object, a function name, arity and parameter value (or list of parameter values) and replaces the old function form with the function's curried form.

  • smerl:rename/2 is a convenience function that takes a function form and returns its renamed form.

  • smerl:curry/5 take a MetaCtx object or a module name, a function name, arity, value and new function name, and returns the curried form after renaming it.



You can read the source for the full documentation.



Ok, enough talk. Let's show an example. Remember my last demo of Smerl's capabilities? Here's the new version, which uses metacurrying:




-module(func_recs).
-export([generate/1]).

generate(Filename) ->
{ok, Forms} = epp:parse_file(Filename, [], []),
lists:foreach(
fun({attribute, _Line, record, {RecName, RecFields}}) ->
case smerl:for_module(RecName) of
{ok, C1} ->
process_module(C1, RecFields);
_Err ->
process_module(smerl:new(RecName), RecFields)
end;
(_Other) -> undefined
end, Forms).

process_module(MetaCtx, RecFields) ->
{_, C2} = lists:foldl(
fun({record_field, _Line,
{atom, _Line2, FieldName}},
{Idx, MetaCtx1}) ->
{Idx+1, process_field(MetaCtx1,
FieldName, Idx)};
({record_field, _Line,
{atom, _Line2, FieldName}, _Def},
{Idx, MetaCtx1}) ->
{Idx+1, process_field(MetaCtx1,
FieldName, Idx)}
end, {2, MetaCtx}, RecFields),
smerl:compile(C2).

get(Idx, Obj) ->
element(Idx, Obj).

set(Idx, Obj, Val) ->
setelement(Idx, Obj, Val).

process_field(MetaCtx, FieldName, Idx) ->
{ok, Getter} =
smerl:curry(func_recs, get, 2, Idx, FieldName),
{ok, Setter} =
smerl:curry(func_recs, set, 3, Idx, FieldName),
{ok, MetaCtx1} = smerl:add_func(MetaCtx, Getter),
{ok, MetaCtx2} = smerl:add_func(MetaCtx1, Setter),
MetaCtx2.


As you can see, there's not a single abstract format for a function in sight :)



What's happening here? The get/2 and set/3 functions are mere skeletons. They are not used directly anywhere in the code. (In fact, when you compile this module, the compiler complains that these functions are unused. Little does it know... :) ) When we process the file person.erl, -- in runtime -- we finally have data we need to embed get/2 and set/3 with the index parameters as well as give them their final names. We achieve this in 1 line of code by calling smerl:curry/5. Not bad, huh?



With metacurrying, I feel that Erlang metaprogramming is finally where it should be. I had thought salvation has arrived in the form (no pun intended : ) ) of fun expressions, but I was wrong (fun expressions are very convenient, but their abstract form is not available in runtime unless you're in the Erlang shell). Metacurrying has finally given us freedom from knowing the Erlang abstract format.



Now Erlang code is just the way I like it: like clay :)



As always, please get the code, give it a test drive, and tell me if you find any problems.



Enjoy!

Thursday, August 17, 2006

Smerl Demo: Easy Function-Based Record Access in Erlang

A few people have told me that they thought Smerl was neat, but they didn't really know what it could be used for. So, I thought I'd share a short demo app that goes a little further than the code snippets in my last few postings about Smerl.



I've heard some people complain about Erlang' record access syntax. I agree with them that the notation Var#RecType.fieldname is not very pleasant to look at sometimes. With Smerl, we can make things better.



Here's a short module I wrote, called func_recs, which generates getters and setters for all records in a given source file:




-module(func_recs).
-export([generate/1]).

generate(Filename) ->
{ok, Forms} = epp:parse_file(Filename, [], []),
lists:foreach(
fun({attribute, _Line, record, {RecName, RecFields}}) ->
case smerl:for_module(RecName) of
{ok, C1} ->
process_module(C1, RecFields);
_Err ->
process_module(smerl:new(RecName), RecFields)
end;
(_Other) -> undefined
end, Forms).

process_module(MetaCtx, RecFields) ->
{_, C2} = lists:foldl(
fun({record_field, _Line,
{atom, _Line2, FieldName}},
{Idx, MetaCtx1}) ->
{Idx+1, process_field(MetaCtx1,
FieldName, Idx)};
({record_field, _Line,
{atom, _Line2, FieldName}, _Def},
{Idx, MetaCtx1}) ->
{Idx+1, process_field(MetaCtx1,
FieldName, Idx)}
end, {2, MetaCtx}, RecFields),
smerl:compile(C2).

process_field(MetaCtx, FieldName, Idx) ->
L = 999,
Getter = {function,L,FieldName,1,
[{clause,L,
[{var,L,'Obj'}],
[],
[{call,L,
{atom,L,element},
[{integer,L,Idx},{var,L,'Obj'}]}]}]},

{ok, MetaCtx1} = smerl:add_func(MetaCtx, Getter),
Setter =
{function,L,
FieldName,
2,
[{clause,1,
[{var,L,'Obj'},{var,L,'Val'}],
[],
[{call,L,
{atom,L,setelement},
[{integer,L,Idx},{var,L,'Obj'},
{var,L,'Val'}]}]}]},
{ok, MetaCtx2} = smerl:add_func(MetaCtx1, Setter),
MetaCtx2.


If the code path contains a module that has the same name as a record name in the source file, Smerl adds a getter and setter to the module for each field in the record. Otherwise, Smerl creates a new module purely in runtime.



Using func_recs is easy. Let's say we have the following source file called person.erl:




-module(person).
-export([new/0]).

-record(person, {name, city}).

new() ->
#person{}.


We can now write the following code:




func_recs:generate("person.erl"),
P = person:new(),
P1 = person:name(P, "Yannick"),
P2 = person:city(P1, "Barcelona"),
io:format("~w is from ~w", [person:name(P2), person:city(P2)])


This example doesn't exactly show you how to build a Google Killer in Erlang :) -- but I hope it illustrates some of the fun things you can do with Erlang metaprogramming using Smerl.



New tip (8/18/06): Are you looking an easy way of knowing what the abstract form for a function is? Fire up the erlang shell and type




io:parse_erl_form(". ").


This will give you a one-line mini shell, in which you can type your function and get back its abstract form representation.

Smerl Attains Erlang Metaprogramming Nirvana (or maybe not)

Update (8/17): Today may not have been my lucky day after all. Apparently, erlang:fun_info doesn't behave identically in the shell and in a compiled module. I'm trying to figure out a way around this but this may be a big roadblock. We may even have to forget about those nice fun expressions and go back to abstract forms :(



...



What does erlang:fun_info do? erlang:fun_info returns a list of tuples that contain metadata about a fun expression -- including the fun expression's abstract form representation.



What did I use it for? To enhance Smerl so that Smerl users never have to to write source fragments or know a single thing about Erlang abstract forms!



Here's the new approach to Erlang (runtime) metaprogramming:




A = 17,
C1 = smerl:new(foo),
{ok, C2} = smerl:add_func(C1, bar,
fun(B, C) -> D = 5, A + B + C + D end),
ok = smerl:compile(C2),
foo:bar(3, 7). %% returns 17 + 3 + 7 + 5 = 32


The astute reader would notice that Smerl supports closures. How? Smerl gets information about closure variables from erlang:fun_info, and expands them in the beginning of the new function. Cool, huh? :)



Another great benefit to this approach is that the compiler now verifies the syntactic correctness of your runtime-compiled code. Indeed, this capability blurs the line between compile-time and run-time Erlang metaprogramming.



I can't wait to see what Erlang developers are going to do with this. I have some ideas in mind but I can't say I know all the possibilities Smerl opens. If you have some thoughts, please share :) Also, please try this out and let me know if you have any problems.



Note: smerl:replace_func now supports fun expressions as well.

Options for Erlang Webapp Hosting

If you're writing a webapp in PHP or Ruby, your have plenty of hosting options. By contrast, not a single company offers Erlang hosting AFAIK . This is a legitimate complaint I've heard from people who are new to Erlang and who want to use it for building a webapp.



Indeed, the web development community has largely overlooked Erlang -- which I'm trying to fix, btw :) -- but this doesn't mean that you're out of hosting options.



Here are the two good options for an Erlang/Yaws app I know of that you may find appealing:




  • The cheap option, which is great especially for the development phase, is to run your app on a VPS (Virtual Private Server). This is actually a nice option for any kind of web development. I'm running this blog on a $20/month VPS server that I'm renting from JaguarPC. I think this is a pretty good package, at least from some research I've done on webhostingtalk.com a while ago, but you might find something even better.

  • When your app is ready for production, you can run it on a rented dedicated server. Such servers are pretty cheap these days ($200-$400 a month IIRC). One interesting hosting provider you should know about is SoftLayer, which lets you set up a 1Gbps private network between multiple dedicated servers. This is ideal for running an Erlang cluster without all the headaches of setting up your own hardware. Softlayer has also been getting good buzz, at least when I've done my research a couple of months ago.



Having your own (virtual) server requires more work than a shared hosting plan, but I think it's great because it gives you full control. For people who are interested in Erlang, I think this is a good fit.



I hope you find this useful! Let me know if you know of any other alternatives.

#1 on programming.reddit.com

Wow, now this is very cool: my article from yesterday, Why Erlang Is A Great Language for Concurrenct Programming, is now #1 on programming.reddit.com. Woot! :)







When I started blogging about Erlang, I never thought it would generate much interest among the larger developer community. I seriously thought, "Erlang so is great, but (relatively) few people use it. I guess people are just not interested in Erlang's benefits, or maybe they are just too attached to OO or procedural languages and they will never be interested in a functional language like Erlang, no matter how great it is."



It looks like I was wrong. I've been getting some great feedback about my Erlang postings, and much of it came from non-Erlangers who've become interested in Erlang just from reading about it in my blog. And now, since my article has reached the #1 spot on programming.reddit.com, I know that Erlang strikes a chord among many developers who are looking for a better -- and more fun :) -- way of creating software.



Side note: it was a strange yet pleasant surprise to see that my article is 5 spots ahead of an article on Paul Graham's website, History of T (Paul Graham didn't write it, though). I'm a big fan of Paul Graham's essays. I've read his book, Hackers and Painters, which is a collection of his essays, from cover to cover. I link to Paul Graham's essays in almost every "long" article I write. I recommend Hackers and Painters to everybody who thinks programming is more than the implementation of specs handed down to you by a suit :)

Wednesday, August 16, 2006

Closing the Loop on Erlang Metaprogramming with Smerl

Earlier today after work, I went jogging in the Hudson River Park. Jogging must do something postivie for the flow of mental juices, because as I was making my way back home, it suddenly struck me that I hadn't fully closed the loop on Erlang metaprogramming with Smerl! Smerl let you add functions to and remove functions from modules, but it didn't let you modify existing functions. Duh!



After I got back home, I sat by my MacBook and frantically hacked away until I fixed this unfortunate omission. I added two new functions: smerl:get_func and smerl:replace_func. You can use smerl:get_func to get the abstract form for a function. smerl:replace_func is a convenience function you can use instead of called smerl:remove_func and then smerl:add_func.



Finally, Smerl has all the capabilites for transforming Erlang modules from solid to liquid and then back to solid.



Does your language let you do that? If not, I think you should seriously forget everything you know and break on through to the other side :)

haXe Now Supports Flash 9!

I haven't blogged about haXe in a while, but this one is certainly worth mentioning: thanks to the amazing work of Nicolas Cannasse, haXe 1.05 was just released today, with support for Flash 9! What does this mean? You can now develop the most cutting-edge Flash apps without shelling any $$$ out to Adobe by using this wonderful open source language that also comes with a blazing-fast compiler (it's written in OCaml ;) ).



For more information, visit http://haxe.org/tutos/flash9.



Also... in case you don't know, I have written a haXe remoting adapter for Yaws, so your haXe clients can easily talk to your Yaws-powered backend. See? You can get the best of both worlds! :)



So what are you waiting for? Go grab that good stuff and start hacking the next great killer app! :)