Tuesday, October 31, 2006

The Correction

If you have finance background (one of my majors was Economics, the others were Math and Computer Science -- but I liked Math the most, especially probability theory), you should know that markets often price equities irrationally. That's due to the crowd mentality that tends to possess investors: instead of buying the bargain stocks that other investors overlook and that give great returns in the long run, they chase the hyped stocks that get all the news coverage, only to eventually see their prices crash and burn.

Although such bubbles happen periodically, they are always followed by a correction: the market wakes up and realizes that it placed incorrect values on certain stocks, leading to the nose-dive of their prices, whereas other stocks rise from obscurity as investors realize what great values they are.

I think we're finally starting to see a correction in the more interesting field (at least, to me) of programming languages :)

erlang_trends.png

Monday, October 30, 2006

New ErlyWeb Zip file

I created a zip file containing ErlyWeb 0.1 and its libraries for easy installation. Check out erlyweb.org for more info.

ErlyWeb Visitor Map, Day 1

Here it is, straight from Google Analytics:

erlyweb_org_map.png

Apparently, Klacke and I aren't the only ones who think that web development doesn't have to suck :)

(Correction: this is the accumulated result for days 1-3, undercounted due to AJAX dependence.)

Friday, October 27, 2006

Introducing ErlyWeb: The Erlang Twist on Web Frameworks

If you've been reading this blog for a while and you've been connecting the dots, you probably know where this is going... :) I you haven't, that's ok -- my old postings aren't going anywhere. There's a lot of Erlang goodness in them for you to soak up at your leisure as you're getting up to speed on this great language.

Without further ado, I present to you the culmination of all of my exciting adventures thus far in the land of open source Erlang:

ErlyWeb: The Erlang Twist on Web Frameworks.

Don't worry, I'm not going to blab for a long time now about why I think ErlyWeb + Yaws is the best web development toolkit available (not that I'm biased or anything :) ). Instead, I decided I'll just take you on a quick tour of how to use ErlyWeb, and let you use your own knowledge about Erlang to fill in the gaps :)

- Get the latest ErlyWeb archive from erlyweb.org, unzip it, and put the zip file's contents in your Erlang code path. (The Erlang code path is the root directory within which the Erlang VM searches for compiled modules. In OS X, it's "/usr/local/lib/erlang/lib". For more information, visit http://www.erlang.org/doc/doc-5.5.4/lib/kernel-2.11.4/doc/html/code.html).

- Download and install Yaws if you don't already have it.

- Start Yaws in interactive mode ("yaws -i") and type in the Yaws shell


erlyweb:create_app("music", "/apps").


(I'm assuming that "/apps" is the parent directory of your Yaws apps.)

This will create an ErlyWeb directory structure as well as a few files. (Note: this initial procedure will probably be shorter when ErlyWeb matures.) This is what you should see:


/apps/music
/apps/music/ebin
/apps/music/src/music_app_controller.erl
/apps/music/src/music_app_view.et
/apps/music/src/components
/apps/music/www
/apps/music/www/index.html
/apps/music/www/style.css


- Edit your yaws.conf file by adding a server configuration with the following docroot, appmod, and opaque directives, then type "yaws:restart()."


docroot = /apps/music/www
appmods = <"/music", erlyweb>

appname = music



- Open your browser and point it at http://localhost:8000/music (note: your host/port may be different, depending on your Yaws configuration). You should see the following page, (breathtaking in its design and overflowing with aesthetic genius, if I may add):

erlyweb_index.png

- Create a MySQL database called 'music' with the following code (thanks, Wikipedia :) ):


CREATE TABLE musician (
id integer primary key auto_increment,
name varchar(20),
birth_date date,
instrument enum("guitar", "piano",
"drums", "vocals"),
bio text
) type=INNODB;

INSERT INTO musician(name, birth_date,
instrument, bio) VALUES
("John Lennon", "1940/10/9", "vocals",
"An iconic English 20th century
rock and roll songwriter and singer..."),
("Paul McCartney", "1942/6/18", "piano",
"Sir James Paul McCartney
is a popular Grammy Award-winning
English artist..."),
("George Harrison", "1943/2/24", "guitar",
"George Harrison was a popular English
musician best known as a member of The Beatles..."),
("Ringo Star", "1940/7/7", "drums",
"Richard Starkey, known by his stage name
Ringo Starr, is an English popular musician,
singer, and actor, best known as the
drummer for The Beatles...");



- Back in Yaws, type


erlyweb:create_component("musician", "/apps/music").


This will create the following files:

/apps/music/components/musician.erl

-module(musician).


/apps/music/components/musician_controller.erl

-module(musician_controller).
-erlyweb_magic(on).


/apps/music/components/musician_view.erl

-module(musician_view).
-erlyweb_magic(on).


Back in Yaws, type


erlydb:start(mysql, [{hostname, "localhost"}, {username, "username"},
{password, "password"}, {database, "music"}]).
erlyweb:compile("/apps/music", [{erlydb_driver, mysql}]).


(The erlydb_driver option tells ErlyWeb which database driver to use for generating ErlyDB code for the models. Note: this may change in a future version.)

Now go to http://localhost:8000/music/musician, click around, and you'll see the following screens:

erlyweb_list.png

erlyweb_new.png

erlyweb_edit.png

erlyweb_delete.png

"Aha!" you may be thinking now, "I bet he's using some Smerl trickery to call functions that contain mountains of horrible code only comprehensible to Swedish Field Medal winners!"

Well.. um, not exactly. In fact, this is the code for erlyweb_controller.erl


%% @title erlyweb_controller
%% @author Yariv Sadan (yarivsblog@gmail.com, http://yarivsblog.com)
%%
%% @doc This file contains basic CRUD controller logic. It's intended
%% for demonstration purposes, but not for production use.
%%
%% @license For license information see LICENSE.txt

-module(erlyweb_controller).
-author("Yariv Sadan (yarivsblog@gmail.com, http://yarivsblog.com)").

-export([
index/2,
list/2,
list/3,
new/2,
edit/3,
delete/3
]).

-define(RECORDS_PER_PAGE, 10).

index(_A, Model) ->
{ewr, Model, list, [1]}.

list(A, Model) ->
list(A, Model, 1).

list(A, Model, Page) when is_list(Page) ->
list(A, Model, list_to_integer(Page));

list(A, Model, Page) when is_integer(Page) ->
Records = Model:find_range((Page - 1) * ?RECORDS_PER_PAGE,
?RECORDS_PER_PAGE),

%% this function makes the 'edit' links in the record ids
ToIoListFun =
fun(Val, Field) ->
case erlydb_field:name(Field) of
id ->
Id = Model:field_to_iolist(Val),
erlyweb_html:a(
[erlyweb_util:get_app_root(A),
atom_to_list(Model),
<<"edit">>, Id], Id);
_ ->
default
end
end,
{data, {erlyweb_util:get_appname(A),
atom_to_list(Model),
Model:db_field_names_bin(),
Model:to_iolist(Records, ToIoListFun)}}.

new(A, Model) ->
Rec = Model:new(),
new_or_edit(A, Model, Rec).

edit(A, Model, Id) ->
Rec = Model:find_id(Id),
new_or_edit(A, Model, Rec).

new_or_edit(A, Model, Record) ->
Fields = tl(Model:db_fields()),
Vals = tl(Model:to_iolist(Record)),
Combined = lists:zip(Fields, Vals),
IdStr = case Model:id(Record) of
undefined -> [];
Id -> integer_to_list(Id)
end,
case yaws_arg:method(A) of
'GET' ->
FieldData = [{erlydb_field:name_bin(Field),
erlydb_field:html_input_type(Field),
erlydb_field:modifier(Field),
Val} || {Field, Val} <- Combined],
{data, {erlyweb_util:get_app_root(A),
atom_to_list(Model),
IdStr,
yaws_arg:server_path(A),
FieldData}};
'POST' ->
NewVals = yaws_api:parse_post(A),
Record1 = Model:set_fields_from_strs(Record, NewVals),
Model:save(Record1),
{ewr, Model, list}
end.

delete(A, Model, Id) ->
case yaws_arg:method(A) of
'GET' ->
Record = Model:find_id(Id),
Fields = [erlydb_field:name_bin(Field) ||
Field <- Model:db_fields()],
Vals = Model:to_iolist(Record),
Combined =
lists:zipwith(
fun(Field, Val) -> [Field, Val] end,
Fields, Vals),

{data, {erlyweb_util:get_app_root(A),
atom_to_list(Model), Id,
Combined}};
'POST' ->
Model:delete_id(Id),
{ewr, Model, list}
end.


And this is the code for erlyweb_view.et

<%~
%% @title erlyweb_view.et
%% @doc This is a generic view template for making simple CRUD
%% pages with ErlyWeb. It's intended for demonstration purposes,
%% but not for production use.
%%
%% @license for license information see LICENSE.txt

-author("Yariv Sadan (yarivsblog@gmail.com, http://yarivsblog.com)").
-import(erlyweb_html, [a/2, table/1, table/2, form/3]).

%% You can add component-specific headers and footers around the Data
%% element below.
%>
<% Data %>

<%@ list({AppRoot, Model, Fields, Records}) %>
<% a(["", AppRoot, Model, <<"new">>], <<"create new">>) %>

Records of '<% Model %>'
<% table(Records, Fields) %>

<%@ new({_AppRoot, Model, _Id, Action, FieldData}) %>
Create a new <% Model %>:
<% form(Action, <<"new">>, FieldData) %>

<%@ edit({AppRoot, Model, Id, Action, FieldData}) %>
delete


<% form(Action, <<"edit">>, FieldData) %>

<%@ delete({AppRoot, Model, Id, Combined}) %>
Are you sure you want to delete this <% Model %>?
<% table(Combined) %>
method="post">

onclick="location.href='<% AppRoot %>/<% Model%>'"
value="no">



Not exactly the stuff that would win anyone the Field Medal, if I dare say so.

If ErlyDB hasn't convinced you that Erlang is a very flexible language, I hope that ErlyWeb does. In fact, I don't know of any other language that has Erlang's combination of flexibility, elegance and power. (If such a language existed, I wouldn't be using Erlang :) ).

The flexibility of components

The notion of component reusability is central to ErlyWeb's design. In ErlyWeb, each component is made of a view and a controller, whose files are placed in 'src/components'. All controller functions must accept as their first parameter the Yaws Arg for the HTTP request, and they may return any value that Yaws accepts (yes, even ehtml, but ehtml can't be nested in other components). In addition, they can return a few special values:


{data, Data}
{ewr, FuncName}
{ewr, Component, FuncName}
{ewr, Component, FuncName, Params}
{ewc, A}
{ewc, Component, Params}
{ewc, Component, FuncName, Params}


So what do all those funny tuples do?

{data, Data} is simple: it tells ErlyWeb to call the corresponding view function by passing it the Data variable as a parameter, and then send result to the browser.

'ewr' stands for 'ErlyWeb redirect.' The various 'ewr' tuples simplify sending Yaws a 'redirect_local' tuple that has the URL for a component/function/parameters combination in the same app:

- {ewr, FuncName} tells ErlyWeb to return to Yaws a redirect_local to a different function in the same component.
- {ewr, Component, FuncName} tells ErlyWeb to return to Yaws a redirect_local to a function from a different component.
- {ewr, Component, FuncName, Params} tells ErlyWeb to return to Yaws a redirect_local to a component function with the given URL parameters.

For example,

{ewr, musician, list, [4]}

will result in a redirect to

http://localhost:8000/music/musician/list/4

'ewc' stands for 'ErlyWeb component.' By returning an 'ewc' tuple, you are effectively telling ErlyWeb, "render the component described by this tuple, and then send the result to the view function for additional rendering." Returning a single 'ewc' tuple is similar to 'ewr', with a few differences:

- 'ewc' doesn't trigger a browser redirect
- the result of the rendering is sent to the view function
- {ewc, Arg} lets you rewrite the arg prior to invoking other controller functions.

(If this sounds complex, don't worry -- it really isn't. Just try it yourself and see how it works.)

Now to the cool stuff: not only can your controller functions return a single 'ewc' tuple, they can also return a (nested) list of 'ewc' tuples. When this happens, ErlyWeb renders all the components in a depth-first order and the sends the final result to the view function. This lets you very easily create components that are composed of other sub-components.

For example, let's say you wanted to make blog sidebar component with several sub-components. You could implement it as follows:

sidebar_controller.erl

index(A) ->
[{ewc, about, [A]},
{ewc, projects, [A]},
{ewc, categories, [A]},
{ewc, tags, [A]}].


'sidebar_view.et'

<%@ index(Data) %>



Pretty cool, huh?

If you don't want your users to be able to access your sub-components directly by navigating to their corresponding URLs, you can implement the following function in your controllers:


private() -> true.


This will tell ErlyWeb to reject requests for private components that come from a web client directly.

Each application has one special controller that isn't part of the component framwork. This controller is always named '[AppName]\_app\_controller.erl' and it's placed in the 'src' directory. The app controller has a single function called 'hook/1', whose default implementation is


hook(A) -> {ewc, A}.


The app controller hook may return any of the values that normal controller functions return. It is useful for intercepting all requests prior to their processing, letting your rewrite the Arg or explicitly invoke other components (such as a login page).

Well, that's about it for now :) I'll appreciate any feedback, bug reports, useful code contributions, etc.

Final words

After reading all this, some of you may be thinking, "This is weird... I thought Erlang is some scary telcom thing, but what I'm actually seeing here is that Erlang is very simple... Heck, this stuff is even simpler than Rails. What's going on here?"

If that's what you're thinking, then you are right. Erlang *is* simpler than Ruby, and that's why ErlyWeb is naturally simpler than Rails. In fact, Erlang's simplicity is one of its most underrated aspects. Erlang's creators knew very well what they were doing when they insisted on keeping Erlang simple: complexity leads to bugs; bugs lead to downtime; and if there's one thing Erlangers hate the most, it's downtime.

ErlyDB 0.7.1, Revamped Driver 0.9.7, Smerl rev 29

ErlyDB 0.7.1
- Fixed a couple of reported bugs (you can look at the issue tracker for more information).
- Added a bunch of functions for getting field metadata from the database. You can look at erlydb\_base.erl and erlydb\_field.erl for more details.
- Added new functions for converting a record to an iolist and for setting its field values from property lists.
- Fixed a bug in the encoding of single digit date values.

Revamped MySQL Driver 0.9.7
- Fixed a bug whereby failed connection attempts could cause process leaks.
- Changed the translation of database null values from 'null' to 'undefined'.

Smerl rev 29
- Improved the module extension mechanism

Saturday, October 21, 2006

ErlTL 0.9.1

In the past couple of days, I've done a lot of ErlTL hacking. Here's what I've accomplished:

- I added support full Erlang function declarations. ErlTL now gives you unlimited flexibilty in function declarations. You can decide what the variables are, add guards, and use Erlang's full pattern matching capabilities. With pattern matching, your don't have to rely as much on cumbersome if-else statements. Here's a sample function declaration that's now legal in ErlTL:

<%@ foo(Bar, {Baz, Boing} = Data) when is_integer(Bar) %>


- I added support for top-level declarations. At the top of your template file, you can now declare Erlang module attributes, compiler directives, and even complete functions (although the latter is not advised as template files aren't meant to contain logic that's better put in a regular Erlang module). One of main benefits is that now you call functions from other templates with less code by importing them. The new syntax for top-level declarations is '<%~ .. %>'. Here's an example:

<%~
-author("Yariv Sadan").
-import(my_killer_widgets,
[foo/1, bar/1, baz/2]).

%% this is allowed, but not advised
pluralize(Noun) -> [Noun, "s"].
%>
<% foo(Data) %>


- I fixed a bug that caused ErlTL to fail to parse multi-line Erlang expressions.
- I rewrote almost all the code. Yes, the last code worked, but it needed to be prettier :)

And finally, here's an example of a complete ErlTL 0.9.1 template:

<%~
%% date: 10/21/2006
-author("Yariv Sadan").
-import(widgets, [foo/1, bar/2, baz/3]).
%>
<%!
This is a sample ErlTL template that renders a
list of albums in HTML
%>


<% [album(A) || A <- Data] %>



<%@ album({Title, Artist, Songs}) %>
Title: <% Title %>
Artist: <% Artist %>
Songs:

<% [song(Number, Name) || {Number, Name} <- Songs] %>


<%@ song(Number, Name) when size(Name) > 15 %>
<%? <> = Name %>
<% song(Number, [First, <<"...">>]) %>

<%@ song(Number, Name) %>
<%?
Class =
case Number rem 2 of
0 -> <<"even">>;
1 -> <<"odd">>
end
%>

<% integer_to_list(Number) %>
<% Name %>



Damn -- now I really can't wait to build those killer Erlang webapps! :)

Tuesday, October 17, 2006

Introducing ErlTL: A Simple Erlang Template Language

Have you ever wanted to build the kind of mail-merge program that never crashes, that runs on a scalable fault tolerant cluster, that you can easily scale by adding more boxes, that you can hot-swap its code without taking it offline, that runs on an optimized VM that can handle hundreds of thousands of simultaneous tasks at a time, and that's built with the same technology that powers England's phone network with a long string of nines after the dot?

If you do, you're probably a dirty scumbag spammer, so go to hell :)

But assuming you're not a spammer and/or you want an easy way of embedding small logic snippets in large swaths of Erlang binary data, you will probably enjoy ErlTL: A Simple Erlang Template Language.

ErlTL does not aim to be the most feature-rich template language. It may not have any time soon that feature that you really like in another template language and that makes your web designers oh so happy. (Of course, you're always welcome to implement it yourself and share it with us. If it's useful, I'll add it to the standard distribution). Currently, ErlTL has 4 main objectives:

- Speed. ErlTL compiles template files into BEAM files prior to execution for top-notch performance.
- Simplicity. ErlTL has the smallest number of syntactic elements that are sufficient for it to be useful (at least, useful for me :) ).
- Reusability. ErlTL lets you reuse templates and template fragments, even from different template files.
- Good error reporting. When you write an invalid expression, the ErlTL compiler makes sure you know on which line the problem is.

Let's take a look at an example. Below is a simple template file called song.et (ErlTL files have the '.et' extension by convention).


<%! This template composes beautiful songs %>
<%? [What, Where, Objects, Action] = Data %>
<% What %> singing in <% Where %>,
Take these <% Objects %> and learn to <% Action %>


Now, let's use this template. Fire up the shell and type:


erltl:compile("/path/to/song.et"),
song:render([<<"Blackbird">>,
<<"the dead of the night">>, <<"broken wings">>,
<<"fly">>]).


If you didn't mess up, this is the output you'll get:


[<<"\n\n">>,
<<"Blackbird">>,
<<" singing in ">>,
<<"the dead of the night">>,
<<",\nTake these ">>,
<<"broken wings">>,
<<" and learn to ">>,
<<"fly">>,
<<"\n">>]


If this isn't exactly what you were expecting, don't panic. For efficiency, ErlTL doesn't try to concatenate all outputs. If you need to concatenate them, you can do it manually, e.g. with iolist_to_binary/1. However, doing so is often unnecessary when you want to send the result to an IO device such as a socket.

So what's happening here? ErlTL creates a module called 'song', with a function called 'render'. This function takes one parameter called 'Data'. (ErlTL also creates a zero-parameter function that calls the 1 parameter function with 'undefined' as the value for 'Data'.) After you compile the template, you can call these functions from template code snippets as well as from any Erlang module.

The template syntax consists of the following elements:


<% [Erlang code block] %>


An Erlang code block is a sequence of Erlang expressions (separated by commas). The result of the expressions is included in the function's output.


<%! [comment] %>


Comments are ignored by the compiler


<%? [top-level expressions] %>


The results of top-level expressions are excluded from the function's output. They are used primary to bind variables to elements of the Data parameter. Top level expressions must go before all standard expressions in the same function.


<%@ [function declaration] %>


Function declarations tell the compiler that all the code following the declaration belongs to a new function with the given name. This is useful when you want to reuse a template snippet. Note that all functions are exported, so you can reuse code by calling functions from other templates. Let's look at a simple example, called album.et:


<%! This template prints an album data in HTML %>
<%? {Title, Artist, Songs} = Data %>


Title: <% Title %>
Artist: <% Artist %>
Songs:

<% [song(Song) || Song <- Songs] %>




<%@ song %>
<%? {Number, Name} = Data %>

<% integer_to_list(Number) %>
<% Name %>



In the shell, type the following:

erltl:compile("/path/to/album.et"),
album:render(
{<<"Abbey Road">>, <<"The Beatles">>,
[{1, <<"Come Together">>},
{2, <<"Something">>},
{3, <<"Maxwell's Silver Hammer">>},
{4, <<"Oh! Darling">>},
{5, <<"Octopus's Garden">>},
{6, <<"I Want You (She's So Heavy)">>}]
}).


(Beatles fans, please forgive me for not typing all the song names! I got tired :) ) This will give you the following output:


[<<"\n\n\n\nTitle: ">>,
<<"Abbey Road">>,
<<"

\nArtist: ">>,
<<"Beatles">>,
<<"

\nSongs:
\n\n">>,
[[<<"\n\n\n \n \n\n">>],
[<<"\n\n\n \n \n\n">>],
[<<"\n\n\n \n \n\n">>],
[<<"\n\n\n \n \n\n">>],
[<<"\n\n\n \n \n\n">>],
[<<"\n\n\n \n \n\n">>]],
<<"\n
">>,
"1",
<<"
">>,
<<"Come Together">>,
<<"
">>,
"2",
<<"
">>,
<<"Something">>,
<<"
">>,
"3",
<<"
">>,
<<"Maxwell's Silver Hammer">>,
<<"
">>,
"4",
<<"
">>,
<<"Oh! Darling">>,
<<"
">>,
"5",
<<"
">>,
<<"Octopus's Garden">>,
<<"
">>,
"6",
<<"
">>,
<<"I Want You (She's So Heavy)">>,
<<"
\n\n\n\n">>]


That's pretty much all these is to ErlTL at the moment. At some point, it may be beneficial to add some iteration syntax, but I'm not planning on doing this in the near future. I hope you find ErlTL useful. As always, please let me know if you have any comments, suggestions or bug reports.

Enjoy!

Note: the current release is in the 0.9 branch in the repository.

Wednesday, October 11, 2006

Recless: A Type Inferring Parse Transform for Erlang (Experimental)

Warning: Recless is highly experimental, and it's not yet finished. Use it at your own risk!!!

My cell phone's favorite feature is the auto-complete mode. With auto-complete, my cell phone guesses what words I'm trying to type based on which words in its database are most likely to match the combination of digits I have entered. For instance, if I wanted to type the word 'hello', I could type '43556' instead of '4433555555666'.

The main drawback is that my cell phone has a limited words database, so when I want to type a word that's not in the database, I have to press some extra keys to switch from auto-complete to manual mode and back again, which is somewhat annoying.

(This happens more often than you would think: the database doesn't hold a single English curse word -- not even 'damn'! WTF :) )

Last week, I had the idea to implement a similar feature for Erlang. In case you haven't used Erlang and you're horrified about the possible implications of the previous statement, don't worry -- Erlang doesn't limit you to coding using only your keyboard's number pad :) However, Erlang does have some idioms that could benefit from some trimming IMO: record getters and setters.

Let's take a detour into a discussion of Erlang's records. Erlang is a dynamically typed functional language. It has no notion of classes and objects. If you want to group a few data elements together, you can put them in a list or in a tuple. To store a fixed number of elements, you use a tuple. For a variable number of elements, you use a (linked) list.

When you use tuples as containers, you have to know the position of each field in the tuple in order to access or change the value of the field. This works well in many cases, and it makes pattern-matching very natural, but it doesn't work well in all cases. Sometimes you want to give a name to a data element and access it using its name, not its position. That's where records come in.

Records basically provide syntactic sugar for tuple creation as well as element access and manipulation. They let you give names to fields, and they resolve the positions for you in compile time. For example, let's say we have defined the following records:


-record(address, {street, city, country = "USA"}).
-record(person, {name, address = #address{}}).
-record(project, {name, owner = #person{}}).


To create a tuple of "type" address and bind it to the variable named Address, you could write


Address = #address{street = "700 Boylston", city = "Boston"},


This would bind Address the value {address, "700 Boylston", "Boston", "USA"}. (The country field demonstrates how to set default values to record fields).

To get the street from an address, you have 3 options:


Street = Address#address.street,
{_,Street,_,_} = Address,
Street = element(2, Address)


Update (10/12/2006): It has been brought to my attention that there's another, perferred way of writing the above logic (thanks, Bengt):


#address{street=Street} = Address,


Changing a record's fields requires additional syntax. Here's an example:


NewAddress = Address#address{street =
"77 Massachusetts Avenue", city="Cambridge"}


Record values can be nested in other records. Example:


Project =
#project{name = "MyProject",
owner = #person{name = "Bob",
address = #address{city = "Miami" }}}


Some people find the standard field access and manipulation syntax somewhat less than beautiful, and I sympathize with them. In almost all OO languages, using properties of an object it as simple as writing 'person.city'. This syntax is obviously more lightweight, but it also comes at the cost of maintaining type data in runtime and/or embracing full static typing. (This is another reminder that no language is perfect -- not even Erlang! :) Actually, many people would say Lisp is perfect... but I digress).

The Erlang record syntax gets even more cumbersome when working with nested records. Let's say we want to get the city of the owner of Project. This is how we go about it using the record syntax:


City = ((Project#project.owner)
#person.address)#address.city


If you think that's an eyesore, consider *changing* the value of the city:


NewProject =
Project#project{owner =
(Project#project.owner)#person{address =
((Project#project.owner)
#person.address)#address{city = "Boston"}}}.


Yes, I know. Ugly. That's why I created Recless.

Recless is a parse transform that uses a type inference algorithm to figure out what kinds of records your variables are holding, and then lets you write much less code to work with their elements. For example, with Recless, the above two examples could be written as


City = Project.owner.city.


and


NewProject = Project.owner.address.city = "Boston".


All you have to do to enable this syntax is to put recless.erl in your source directory and add the following declaration at the top of your source file:


-compile({parse_transform, recless}).



The holy grail for Recless is to Just Work. There is, however, one main restriction in Recless's type inference algorithm: function parameters must indicate their record types for type inference to work on them. For instance, this won't work:


get_name(Person) -> Person.name.


Instead, you must write this:


get_name(Person = #person{}) -> Person.name.



Recless is already pretty good at figuring out the types of your variables, but there are many cases that it doesn't handle yet. It also probably has some bugs. The reason I'm releasing it now is that when I got the idea to make Recless, I seriously underestimated how hard it would be to make it. I thought it would take 2, at most 3 days, but I've already spent more time than that, and I'm only 75% or so done. Before I dig myself any deeper, I wanted to get some feedback from the Erlang community. If many people want Recless, and everybody agrees that Recless can't mess up any code that's written in standard Erlang, I'll devote the extra time to finishing it. Otherwise, I'll go back to other projects and maybe finish it later when I have some more time.

You can get the source for Recless here: http://code.google.com/p/recless. It also includes a test file that demonstrates what Recless can do at the moment.

Note: Although Recless does a good amount of type inference, it does not attempt to catch type errors. Dialyzer already does a fantastic job at that. All Recless tries to do at the moment is simplify record access and manipulation syntax. If Recless fails to infer the type of an expression such as "Person.name", it crashes with a type_inference error (this will be improved up if/when Recless grows up).

I'll appreciate any feedback!

Tuesday, October 10, 2006

Going to the Erlang Conference

I'm not exactly enjoying what one would call a "positive" cash flow these days, but I decided to dig into my hard earned budget anyway and spend a chunk of it on a trip to Sweden for the 12th annual Erlang conference.

Here's my dilemma: I want to take this opportunity to make a 2 week backpacking trip in Europe. I want to see Sweden, but I'm afraid it will be too cold to enjoy in the winter. I can either stay in Sweden after the conference, or hop on a plane to France or Spain (I *really* want to visit Barcelona).

I'd appreciate it if anyone could give me some tips on what I should do.

To save money, and also to stay true to the spirit of backpacking, I'll be staying in hostels, which means I probably won't bring my MacBook. I hope that spending 2 weeks without a computer won't result in serious withdrawal symptoms.

Monday, October 09, 2006

Blogging About Erlang

Wow. I read today some of my old articles and I must say I wish I had spent some more time refining them before I hit that 'publish' button. They're not all bad... Even the more enthusiastic ones are definitely amusing at least for a personal blog of a hacker discovering a wonderful new toy. However, now that my blog became more popular than it had been when I wrote most of them I feel that it calls for a more sober writing style. I have learned that many of my readers are quite hype-weary from J2EE and then Ruby being sold to them as the Next Great Thing, and the last thing I would want is for them to feel the same about Erlang.

ERLANG SUCKS. DON'T USE IT!!! STICK WITH RUBY!!!

There. Now nobody can accuse me of hype instigation :)

Then again, maybe my initial learning towards a controversial writing style has drawn more people's attention to my blog, and I'll do anything to serve The Cause... Just kidding... :)

I think most reddit readers have gotten by now what makes Erlang different. From now on, I will let the language sell itself, and focus my writing about the topic about which I care the most: the code.

(I also promise I will never write an article about Agile development. I don't even know what it really means!!! I guess my ignorance makes my coding Sluggish :) )

Believe it or not, I don't care *that* much if Erlang becomes mainstream. It would be great if many people used it, if for no other reason than the satisfaction they would experience by using a real functional language that makes concurrent programming a joy. The main reason I started blogging about Erlang is that I recognized it would be a great tool writing certain apps, and the last thing I wanted was when people would me how I built something and I would say, "I used Erlang," they would ask "ErlWhat???"

Despite my nitpicking, I'm pretty happy with the way things have played out so far. From other articles I'm reading these days, I get the impression that now many more people understand and respect Erlang. If nothing else, I have a lot of respect for the people who created Erlang because they have solved some of the hardest problems in creating tools for building scalable, fault-tolerant, distributed systems -- an area that feels mostly abandoned by most programming languages. They also gave their creation to us for free. I wouldn't be as good a programmer if I hadn't spent the time using Erlang and learning what makes it special.

In the spirit of American capitalism, I should try to make a buck from my blog. Therefore, expect my new book to hit the stores in two months: Sluggish Development With Erlang for the Hype-Averse, Battle-Scarred Programmer :)

Wednesday, October 04, 2006

Today's Innovation Prize Goes To...

the City of Boston -- for its solar-powered trash compactors!

IMG_2102

I must praise this compactor for its fault tolerant design: even if the power grid fails, it keeps compacting away. Very Erlangy :)

(Alas, if the sun fails, it is in trouble -- but then we'd have bigger problems to worry about :) )

Tuesday, October 03, 2006

Going to the Paul Graham Talk

After weeks of bombarding me with tedious Erlang hype, reddit has finally given me a useful link: Paul Graham (whom I've been accused of over-quoting :) ), will be speaking tomorrow at MIT. (For literal minded people -- I didn't mean the first part of that sentence seriously :) ) It's a free talk that's open to the public.



Is anybody who reads this blog going?