Monday, November 27, 2006

Java metaprogramming: the masses are ready.

defmacro smallHibernate(tableName, arrayFields) {
  class <%=tableName%> {
   <%for(int i=0;i<arrayFields.size();i++) { %>
    public <%=arrayFields.type%> <%=arrayFields.name%>;
   <%}%>
  }
}

smallHibernate {"Employee", new Field("String","Name"),new Field("int","Age")};

Generates:

class Employee{
  public String Name;
  public int Age;
}

Metaprogramming is the ability to write programs that, in turn write another programs. Metaprogramming is at the core of Lisp, that highly academic, largely ignored language. However, Lisp programmers feel somehow "superior" to others programmers. Writing Lisp is a really different experience than writing software in any other language. The Nature of Lisp is to leverage the language towards your problem; to write a Domain Specific Language on top of Lisp and then solve the problem. This has been known for a long time by some highly skilled programmers, and it has remained this way until now. Metaprogramming is no longer the realm of academics, hackers and gurus. Metaprogramming is for everyone today; you know what? You have been metaprogramming for quite a long time, and you have been using DSL's for a while too.

Have you used JSP, ASP or PHP? Then you know what metaprogramming is. Take a look at this code:

<html>
  <body>
   <?php echo "Hello World"; ?>
  </body>
</html>

You understood it? It's quite simple! Actually this is a piece of code that outputs a different piece of code. PHP code gets executed on the server, a piece of HTML code is generated and then sent to the client. Let's see another example, this time in ASP just to prove that even Microsofties can metaprogram :P

<html>
  <body>
   <% response.write("Hello World!") %>
  </body>
</html>

I'm sure you understood this one too; it's really easy. What I am trying to demonstrate here is that the idea of metaprogramming is simple and well known for all developers in the world. We all have written programs that generate code as an output before so, no mystery here, anyone can metaprogram.

Now I am going to demystify DSL's. You have used a number of DSL's before. Take a look at this:

SELECT * FROM employees WHERE age > 50;

It is really easy, isn't it? SQL is a Domain Specific Language, is a language that can only be used to query databases. You cannot write a 3D engine in SQL. You cannot write yet another ERP using SQL. SQL is good for querying databases and nothing else. However, SQL is so good at it, and querying databases is so common that we all know have learned it.

But this not the only DSL you know about,; in fact you are surrounded by DSL's. Have you used (N)Ant? Ant is a DSL for compiling projects. Again, you cannot use Ant to write any kind of program, but as build scripts are a common problem, we all learned Ant. Because it is really good to solve the problem it has been designed for; that's why we use it.

O.K. then, I have stated two main ideas so far:

* Every programmer in the world is now used to metaprogramming because of HTML generating languages as PHP or ASP.
* Every programmer in the world is now used to DSL's like SQL or (N)Ant.

Then, why is it so difficult? Why aren't you metaprogramming in your project right now? Well the answer is that most likely your favorite programming language does not support it. Even if it does, it forces you to use some kind of weird, difficult sublanguage like C++ Templates.

Historically, only difficult, academic languages usually oriented to functional programming like Lisp or Haskell have had good support for metaprogramming. This languages not only support metaprogramming, they support a whole range of other "difficult" things like first order functions and the like. Metaprogramming is entangled with a lot of others advanced characteristics and is not well understood by regular programmers.
And the syntax, too. Lisp syntaxs is horrible, with all those parenthesis.

But now Java is open source so everyone can fork. And the masses are ready. Ready for metaprogramming in a "real" (as in "non academic") language: Java. Did you understood the code at the beginning of the article? Did you find it useful? If both answers are positive, then I´m right: the masses are ready.

4 comments:

Anonymous said...

En el código de ejemplo, has puesto la llamada con los campos en inglés y el resultado con los campos en español :P Cámbialo para que los lectores ingleses no se líen ;)

-Walenzack.

McPolu said...

Hecho, gracias!

PerkiPat said...

Also in C language we have macros due to the preprocessor, don't we?

#include <stdlib.h>
#define res(name,type,qu) type *name;\
if( (name=(type *)calloc(sizeof(type),qu))==NULL )\
{\
perror("Not enough memory");\
exit(EXIT_FAILURE);\
}

int
main(int argc, char **argv)
{
res(buf,int,4);

free(buf);
}

preprocessed (and tidied a little), it becomes:

int
main(int argc, char **argv)
{
int *buf;

if( (buf=(int *)
calloc(sizeof(int),4))
==((void *)0) ) {
perror("Not enough memory");
exit(1);
}
;

free(buf);
}

Well, it is not the same, because I can do this when I compile, but not while in run-time. My program at run-time couldn't "imagine" a class and create it.

Almost half year ago, I read Paul Graham's Hackers and Painters, and there he speaks a lot about Lisp. He says among other things that most of the current languages (perl, python, ruby, java, etc.) are gradually taking ideas already developed with Lisp in 1958, although it's true that the Lisp syntax is absolutely horrible.

More about him (some of his essays): http://www.paulgraham.com/

promoteyourblogforfree said...

nice blog