Wednesday, February 20, 2008

Scheme For Enlightenment Part twenty - Scheme Is Hackable

Having written this much English about Scheme, i now feel minimally competent to address one of the things that really bothers me about the Guile Reference Manual. Section 4.6.2 is entitled Why Scheme is more hackable than C. This hasn't been my experience, so i'll take the issues point by point, and be as fair as i can in my infinite bias.

* They [interpreted languages] lend themselves to rapid and experimental development cycles, owing usually to a combination of their interpretability and the integrated development environment in which they are used.

There are C interpreters. They are usually sold as debuggers. C compiles very fast. On a 1987 Macintosh II (about 1 MIPS) the Think C (then Lightspeed C) compiler could scan code at effectively 70,000 lines per minute. And, since it only needed to recompile modules that changed (perhaps due to include files), it typically only needed to recompile a few hundred to a thousand lines, taking less than a second. Further, the integrated debugger remembered break points, variable watches and so on, so a single key stroke compiled your code, ran it, and stopped at an interesting breakpoint in seconds. C interpreters often get to this point later, because the interpreter runs code much slower. Interpretive systems like Scheme, Perl, and so on have little to add to this. Unless, while stepping through your code, you see an error, modify your code and continue stepping. To date, the only language system i've used that supported this was C (using a C interpreter). And Guile performs a compile, though without saving it to disk. It can get away with this because compiles are so fast. The interesting bit is that the user doesn't have to do something special to make it happen. The user is very slow compared to the computer, so compiles are invisible. But even Emacs with gcc and gdb is an environment that is integrated enough to be quick. Emacs has a compile command that puts the errors in another window, and can quickly move the cursor to some line that caused an error or warning. It's very fast.

* They [Scheme and other languages] free developers from some of the low level bookkeeping tasks associated with C programming, notably memory management.

This is true. At least this isn't a totally lame argument. It is unfortunate, but at least at the moment, the human is capable of managing memory such that the overall performance is much higher than machines, despite enormous research into automatic memory management (mostly garbage collection). Explicit memory management is faster but more error prone. But Scheme replaces that task with the bookkeeping of managing parenthesis. So far, this one misfeature seems much worse than the syntax headaches that C presents. There are other handy abstractions, but unfortunately, this very ripe area is left unpursued.

* They provide high level features such as container objects and exception handling that make common programming tasks easier.

It may be that C has simpler (and less flexible) scope rules than Scheme. Learning Scheme's scope rules may simply take longer. The most challenging limitations in C's scope rules show up when writing libraries. If a library is viewed as an object class, then the library will want it's own class variables. The library must choose some names, and some could conflict with the names used in other libraries. But C's names are no longer limited to 7 characters, as they were on the PDP-11 with Ritchie's original C compiler. And name conflicts can be limited by using naming conventions. These conventions can be broken when it makes sense, so C retains flexibility. The Java convention for naming classes tries to make name conflicts impossible world wide. It's a very ugly solution. Container objects and exception handling can certainly be done in C. The resulting syntax looks much as it does in object oriented languages. One can use it if they want to. I personally don't find exception handling, that is try and catch, to be easier in most cases. It can get in the way really good error handling, that matches the problem at hand. My highest praise for try and catch is that novice programmers may be encouraged to think about error handling, at least at some minimal level. But it's both complicated and minimal. In the few cases where it is needed, often a simple setjmp/longjmp setup is often sufficient.

Additionally, library writing is relatively rare. Most code is not easily reused. Most code is designed to solve the problem at hand. Certainly, hacking (playing around with some ideas) is not library writing. So, languages with no scope rules, like BASIC, are significantly more hackable than languages with strict scope rules like Scheme. That should sting, being compared to BASIC and coming up short, even on one point of many. But compared to BASIC, essentially all languages are unhackable.

No comments: