A rant on prototype.js, and how to compile code.I had gotten the hint that prototype.js is not the only game in town, so I looked up some stuff on this whole AJAX mess. Yes, it's pretty cool to combine all these technologies together. No,
Sam Stephenson is not a saint. He is, however, quite a programmer.
From reading his prototype.js code, it's clear to me that he's spent quite a lot of time and effort cleaning up after browser bugs and incompatibilities. On the other hand, he also expresses a political agenda in this code, and one with which I disagree. No, it's not the MIT license. Actually, I'm happy that he used that one, because it means that I can copy the parts I like and gut out the rest.
"What's the agenda," you may ask.
It seems that our dear Sam has become so infatuated with Ruby's style of OO programming and block-passing that he undertook to recreate the same concepts, but with javascript syntax. There's nothing wrong with a little experimentation, but I think that trying to wrend language concepts at this level is misguided.
Sure, Javascript lets you pass functions around as parameters, and call them, and so forth. Sure, you can write anonymous functions, and place them anywhere in code as a value of the first order. Unfortunately, playing such games as he does with the syntax doesn't actually buy you much. Compared with a language like Smalltalk or Ruby where creating a callable block is about three or four characters, JS requires quite a bit more visual noise to create an anonymous function. There's more ceremony to it. It looks bulkier.
Maybe you want to write in a functional style. I've experimented with the same ideas in PHP. People who understand the general ideas involved will follow your code with difficulty because of the linguistic dissonance that comes from using a language built around Algol principles. You can't, for example, in PHP, create a partial (or curried) function without all the syntax of a whole function, or at least a fairly explicit function call which has to be explained in detail to the uninitiated.
Yes, I think Haskell is a great language. Yes, Lisp can do these things, but I don't plan to use Lisp in the near future. These are languages with support from the most basic foundations for composing parts of functions to express greater and more powerful wholes.
PHP and JS don't operate that way, by nature.
In Javascript, we're given a completely different worldview. Everything is not inherently a recursive algorithm which the compiler mysteriously changes into an iterative implementation when it's both possible and correctly incanted by the programmer. The basic idea is that people can express a set of steps easily, but trying to explain a process in terms of functions is more difficult.
Get that. Algol-style languages are about process. Lisp-style languages are about function. Both are valid perspectives, and each will yield great productivity for people who apply them well. When you apply the wrong technique, it's like trying to pound a nail using a screwdriver. You might get somewhere, but it's a lot more effort than it's worth.
Way back in the heyday of the structured-programming debates, someone wrote a book by the title of "Structured Programming". (Fancy that.) I don't recall the author, but I remember reading the book. In this day and age, so much of the results are taken for gospel that much of the thought process leading up to current structured programming practice seems forgotten in the noise and hype about the greatest new language.
Now, before you get your hackles up about the second-most-ancient programming paradigm being so old, please understand that all object-oriented programs are structured. Structured programming is just the idea that common themes found in the practice of programming may be factored away from the expression of any particular algorithm and replaced by something equivalent, more concise, and less error-prone. Structured programming (SP) is absolutely as relevant today as it was when the idea was first formalized.
You have to look at the development of the SP idea within it's historical context, though, to get a good understanding of why we are where we are today.
Early on, people who had been used to working with process flowcharts and dramatically smaller data processing tasks noticed that the most common overarching patterns were the loops, conditional branches, multiplexing, and function calls that now commonly populate reference manuals for Algol-family languages like C, Basic, Pascal, Java, Javascript, PHP, and so forth. We typically think of these as control structures. That's because the people who created and named them were out to solve problems of control. They didn't need to worry about higher-level concepts yet, because:
- control is the most basic quality of a process, and,
- these languages are based on expressing process.
There was one major thing that Lisp and its ilk did completely differently. Actually expressing the discrete steps of a process in Lisp is rather difficult, but you can do it once and trivially pass in executable code as a parameter to how the process should work. In short, you can (with some difficulty) make your own control structures in Lisp. If you know enough about how the Lisp interpretter (or compiler) works, then your control structures might even be computationally efficient.
Ruby is quite a nice language because you can create your own control structures fairly easily, and yet it's a process language at root, so it's easy for people to understand what's going on. In truth, there are limitations, though. If you want the really pretty syntax that Ruby offers for custom control structures, then in fact you're limited to structures that simply wrap a block of code. You can't, for example, create a C-style for(;;) loop from scratch purely with Ruby's syntax for custom control structures. On the other hand, I have little doubt that Lisp offers such ability, even if the actual syntax might not be so familiar to us process-description folks.
Sam is trying, with prototype.js, to create his own control structures. Javascript can be pushed in this direction, but it's an uncomfortable push. You face weird limitations and awkward syntax.
What you probably really want is more like a macro preprocessor that turns uber-Javascript into executable Javascript, and uber-PHP into executable PHP. You express your higher-level concepts for code organization in this other language, and then let the computer do the harder work of converting this smaller, easier, and less-error-prone version into something that the browser can actually run.
Some would say that you've re-created Lisp, or Scheme, or any one of its variants.
Imagine this sort of thing:
To reduce a sequence, given an initial value and a function of two values:
- If the seqence is empty, return the initial value.
- Remove the first element from the sequence and call it "head".
- Apply the given function to the initial value and the head, and take the result to be the new initial value.
- Go back to step one.
As you can see, it's not hard to express a totally general process using completely procedural English. The correctness of the algorithm should be self-evident, and you don't need a strong understanding of recursion to write the program correctly the first and only time. From then out, if your macro language allows you to compose definitions, you can say things like:
To get the sum of a sequence, give the initial value of zero and the function of addition to the reduction procedure. Return the result.
Presumably, your macro processor would be able to write all the code necessary in the target language to produce the desired result. In short, it would produce a function for summing sequences of numbers, and that function would work, and we would absolutely not care how or why it worked.
That is called compiling a program. The only difference here is that we're using something other than machine code for the target language.
Ok, rant over with.
Anyway, I've got deep dark plans on this subject for much later on.