Wednesday, December 21, 2011

A compile-time debugger?

Today, I've been thinking about templates: the second hardest bits of code to read in any given C++ program. (The very hardest, of course, would be the error messages that the templates generate.)

And, as is my tendency at such times, I've been thinking about how to do a better job in my programming language, Swym. All the cool languages are into type inference these days, and I'm keen for Swym to do it too - but I'm worried that global type inference (as opposed to local type inference like the "auto" keyword, which seems just fine) will lead inevitably to bad error messages.

In that sense, Haskell's type error messages and C++'s template error reports find themselves in a similar situation: there's a chain of types, and one end doesn't match the other. Somewhere along the chain, something went wrong, and we need to tell the user what happened.

C++ just spews out information about the whole chain, which gives you an unreadable a wall of error messages. Haskell's approach is to pick a place and tell you about it. All things considered, it picks fairly good places - but inevitably, there are times when it picks the wrong part of the program, and there's no way to get more information about what else it might have highlighted.

So I was thinking... well, really, we'd like the best of both worlds. Let the compiler tell me its best guess about where it went wrong, but somehow give me the option to explore further. A lot like a call stack in a debugger. "Wait, it thinks parameter x is an int? Where did it get that idea from?" (back out) "Oh, apparently f is returning an int now?" (drill into f)... etc.

This is a fascinating idea. Think about it - when your program crashes at runtime, you can attach your debugger and see exactly what was going on. Wouldn't it be nice to be able to explore the program state at compile time, in exactly the same way?

This supports some other ideas I've been toying with, too. In Lisp, you can write arbitrary code that runs at compile time. Why aren't there any tolerable languages that let me do that? (Sorry Lisp fans, I tried, but I really can't handle the parens). And if you're writing arbitrary code... well, if it crashes, what happens to the compile?

Clearly it's time to start writing a Swym debugger. One that can run at compile time AND run time. :-)