Compile Time Languages

Compile Time Languages

Let’s say I want to call a stored procedure in a database. The stored procedure is called GetBooksByAuthor, and takes one parameter, “author”, which is a string.

It would be nice to call it like this:

But how do we do that? Currently, there are only a few ways I can think of:

  • A code generator could connect to the database, obtain all the stored procedures, and populate a class called “database” with the appropriate functions
  • The same thing, but we could interact with the generator to only get a few stored procedures. Of course this means that we have to manually intervene every time we need a new procedure.
  • We use a dynamic language, which is able to take the function name as the string “GetBooksByAuthor” at run-time, and dynamically populate the call to the database

The code generators are generally a bad idea. For one thing, they generate code (and normally pretty bad code), which just clutters up the real code. They also require a separate step. Before we code against a new stored procedure (or a changed one) we need to (re)generate the code that proxies for the stored procedure. This can’t be done automatically, since it happens before we code (otherwise the auto-completion and wonderful things like that wouldn’t work).

Also, in the case where we don’t do a brute-force fetch-all approach, we also need to specify which procedures we want to bind to. This list of procedures is probably stored with the code generator and not with the code that actually calls the function. This is terrible for code locality. Often the generated code will be part of the data-access-layer of the program, while the code that actually uses it will be somewhere else.

On the other hand, if we use a dynamic language, we lose quite a few things:

  • Static type checking
  • Performance
  • Auto-completion and other IDE assistence

But what if we could get the best of both worlds? What if we could use “dynamic” functions, but execute them at compile time? Consider this example, based on a hypothetical language which is related to C#:

In the above example, it would pretty much just “work” in C# if you took out the words “meta” and “static var” – although the database.GetBooksByAuthor would instead look like database.Call(...). The word “meta” would simply tell the compiler to translate calls from the form database.GetBooksByAuthor(...) into calls of the form database.call("GetBooksByAuthor", ...). This is nothing interesting, and has nothing to do with compile time vs runtime – it should work the same either way (in this hypothetical language).

Why are there two connection strings? Well, you might not notice it, but normally there are two connection strings. You use one connection string in your development/build for your code generator or IDE, and often a different connection string (provided dynamically as a configuration) for your production environment. The above program just makes it more obvious – and it also puts them in the same place.

This example would work perfectly fine at run-time. But the interesting thing is what happens if you use partial-evaluation to specialize the Database class at compile time. In particular, I think the runtime program could be simplified by the compiler down to the following:

Moreover, since a lot of it can be evaluated at compile time, the IDE could also provide auto-completion and other information. For example, when you type “database.”, the IDE can provide a list of stored procedures (by executing user code).

Taking it further

This could be used for more than database access. It could be used to provide linking to files of completely different languages, even if they exist in the same program. You wouldn’t need compiler extensions to be able to link to C++, all you would need is a library which knows how to call a C++ ABI.

Leave a Reply