Tuesday 16 December 2003 — This is 21 years old. Be careful.
Hacking around with PostScript, I’m being reacquainted with its unusual language structure.
The whole thing is stack oriented, like Forth. Adding two numbers is done by pushing the two numbers on the stack, then invoking the add operator, which pops two numbers, adds them, and pushes the result:
2 2 add % leaves 4 on the stack
Control structures work the same way.
The ifelse
operator takes
three things from the stack: a boolean and two executable blocks.
If the boolean is true, it executes the first block and discards the
second. If the boolean is false, it executes the second block and
discards the first:
1 2 eq { (y) } { (n) } ifelse % leaves "n" on the stack
The for
operator is used for looping.
It takes a start value, an increment, an end value, and an
executable block as operands:
% Calls doSomething ten times with 1 through 10 as arguments
1 1 10 { doSomething } for
Here’s where it gets tricky: these control operators take their values from the stack, and it doesn’t matter how the values got there. Often, as in these examples, they’ll have been pushed there by literals just before the operator is called. But they can be placed there any other way, and the operators will still work:
% Loop up or down, depending on the value of up?
up? { 1 1 10 } { 10 -1 1 } ifelse
{ doSomething } for
This will loop from 1 to 10 if up? is true, and from 10 to 1 if up? is false.
Also, because executable blocks are objects on the stack that can be passed around and manipulated like any other object, you can write your own control operators:
% probability block 'domaybe' -
% Excecute the block randomly, determined by the probability.
/domaybe {
exch % bring the probability to the top
1000 mul % scale the probability to 0-1000
rand 1000 mod % pick a random integer in 0-999
lt % should we execute the procedure?
exch % swap args to make them right for if
if % execute the block if we should
} def
.01 { veryInfrequently } domaybe
.95 { almostCertainly } domaybe
Not that you’d want to build large systems in PostScript, but it’s good to bend your brain in different ways occasionally. Smalltalk has a similar build-your-own-control-structures descriptive power, though it is not stack based.
Comments
This ability to define language extensions with the same power sort of expressive power as the base language doesn't seem to be too popular these days. I guess it's more interesting to language researchers or defining domain-specific "little" languages than the general community of developers.
The problem with this sort of power is it can easily result in "write only" code.
In the business process world there is a raging debate around PI Calculus (Barry Briggs among others has been chiming in). My take on PI calculus as I tried to follow some of the threads was that it required lambda calculus and this is the basis for languages like lisp (self-referential capabilities being one of them).
Stack languages like Forth ... I actually don't like them (ever worked with APL?) ... but will use them to build things like FSMs, certain types of dataflow managers, etc.
I'll go way out on a limb here ... the .NET CLR is as close (if not more in some respects) to what I could do with a lisp machine nearly 20 years ago. One-time use of delegates launched on an async thread are equivalent (in my opinion) to closures in lisp/scheme and are incredibly powerful. I was initially anti-.NET ... but I'm now very much pro-CLR and am eagerly awaiting some of the features being alluded to in the next release (hinting for the garbage collector -- very powerful when coupled to use of Interops).
I agree that the .NET CLR is very powerful and is evolving in interesting ways. Beyond the power that you mention, I think its clear that we're turned a corner here. We're finally developing in "safer" languages with GC as the norm. We don't spend cycles chasing down memory leaks, bad pointer references, bad array indexing, etc.
Alternative formulations:
What leads a man to write postscript?
What horrible thing did your computer do to you to drive you to write postscript?
Particularly interesting is REBOL's grammars-based parsing, which gives programmers much of the power of REGEX while allowing easy creation of domain specific languages (little languages, etc.).
Add a comment: