ScriptPost [entries|reading|network|archive]
simont

[ userinfo | dreamwidth userinfo ]
[ archive | journal archive ]

Tue 2018-08-28 09:18
ScriptPost

I've been handwriting PostScript on occasion for more than half my life – it's one of those odd side skills that comes in handy more often than you might think – and somehow I think yesterday was the first occasion I can remember when I had to swap the values of two variables.

Usually, in a language where the assignment operator can only change one variable at a time, the idiom for swapping two variables requires three statements, using a temporary variable to save one value in at the point where you've just copied the other value from one variable to the other (so they both hold the same value).

PostScript is such a language. The syntax for doing a swap that way (supposing the variables you're swapping are called foo and bar) would be

/tmp foo def
/foo bar def
/bar tmp def

in which, for example, /tmp pushes a variable name on the operand stack; foo pushes a variable's value; and the def operator pops both of those operands back off and writes the given value into the variable identified by the given name.

But this is excessively roundabout. PostScript may only let you assign one variable at a time, but its stack structure lets you avoid defining a temporary name: in order to save the old value of the first variable, you only have to push it temporarily on the operand stack, and recover it after the redefinition of the other. For example:

bar            % push the original value of bar
/bar foo def % set the final value of bar
/foo exch def % set foo to the value pulled back off the stack

But a neater way avoids even the need for that exch:

/foo bar       % parameters for the 'def' that will set foo
/bar foo % parameters for the 'def' that will set bar
def % set bar, using the second pair of params
def % set foo, using the first pair

or, once you're using it in anger and not explaining it every time,

/foo bar /bar foo def def

I thought that was unexpectedly cute! It's got the same set of words as the two separate assignment operations ‘/foo bar def’ and ‘/bar foo def’, but it uses the fact that PostScript assignment ‘statements’ are in some sense not atomic specifically, that the evaluation of their RHS and the enaction of the assignment itself can be separated – to interleave those two statements in a way that avoids the usual problem.

And that's why I think I can't ever have had to do that before – if I had, then surely I'd have run into this mild cuteness already!

LinkReply
[personal profile] ptc24Tue 2018-08-28 09:24
Reminds me of Forth.
Link Reply to this | Thread
[personal profile] simontTue 2018-08-28 09:59

Not surprisingly – PS and Forth have the common feature of being essentially RPN-shaped languages based around an operand stack, so they look quite similar in some ways.

But PS is higher-level. Forth deals in addresses and pointers: declaring a variable allocates space for it (somewhere) and defines the variable's name as a word that pushes the address of that space, so even reading a variable requires a word for "dereference" (if I remember rightly, "varname @" is the rune), and the word to set a variable ("!", I think) is the same as the word for "store this data to some other arbitrary memory address I've come up with by other methods".

By contrast, PS is all logical data types with garbage collection and doesn't give you access to the underlying address space at all. Instead, it has the Lisplike concept of symbolic name tokens (written with that leading /, unlike Lisp's really awkward unmatched quote character), and also a dictionary data type not unlike your Perl/Python hash / dict / associative array. Dictionaries can be used explicitly as user variables using the get and put operators, but there's also an implicit stack of them that hold the current variable scopes, so what "/foo value def" really means is "add the key-value pair (/foo, value) to the dict at the top of the current scope stack, overwriting any previous value that went with that key".

But yes, I suppose that this same idiom for variable-swapping would work very similarly, in that if you'd do a normal Forth assignment by saying

srcvar @ destvar !
then you can do a swap by saying
var1 @ var2 var2 @ var1 ! !
or perhaps it looks neater to rearrange things a bit:
var1 @ var2 @ var1 ! var2 !

Link Reply to this | Parent
[personal profile] tigerfortWed 2018-08-29 17:14
Passing irrelevant side-note: a guy I worked with long ago amused himself during a couple of slow patches by playing around with postscript. This included writing a (surprisingly short) program that generated a random (single-solution, ie wall-bangable) labyrinth in the memory of the printer (and then printed it).

The path width had to be set before you sent the PS file to the printer, of course, and for a narrow path, running the program tied up the office printer (late 1990s laserjet) for a VERY long time.
Link Reply to this | Thread
[personal profile] simontWed 2018-08-29 19:10
I have a vague memory of someone I know plotting a Mandelbrot set by means of sending a PS program to calculate it to the nearest printer. (Possibly [personal profile] fanf, unless he did a different silly thing with Mandelbrot sets.)

I think my own daftest piece of tricky computation in PS was a program that traced round the boundary of a connected set of cells in a grid, by using a system of dictionaries and arbitrary keys to mimic the kind of pointer-chasing data structures like trees and linked lists that you'd build in a C program for a similar job. (The idea was to plot a series of diagrams showing the solution to a block puzzle: I'd provide a set of data tables showing how high each column was piled up, and the program would autodetect which columns had changed from the previous diagram and outline them so you could see where the next piece had to be placed.) There was also a completely non-printing-related school maths project that I chose to write in PS because it was the most obscure language I could think of at the time and I wanted to annoy the maths teacher, but sadly I've completely forgotten what that one actually was.

(I wanted to annoy the teacher in petty revenge for an unreasonable complaint she'd made about my previous use of a computer, along the lines of ‘I told you to write a program for this, but your answer is is only one line long, so it doesn't count’ – well, then set a challenge that requires more than one line to solve!)

My dad may still hold the family award for evil PS, though, in spite of my best efforts. He wrote a Postscript program to print out a text file, not only wrapping lines and splitting it over multiple pages, but also interpreting a fairly complete set of DEC terminal-style escape sequences (in fact much the same subset supported by DEC dot-matrix printers of the '80s, such as the LA75). The kicker was that this program was a prologue: you'd send it to the printer immediately followed by the literal text file itself, and the PS prologue would start reading from currentfile at just the point where it ended and the text file began. (DSC? Who needs it.) So the kind of print job I'd now construct by running Enscript or a2ps or some such would simply have been cat prologue.ps foo.txt | lpr, or rather, the VMS equivalent.
Link Reply to this | Parent | Thread
[personal profile] womumpSun 2018-09-02 11:41
I thought I had remembered an instance of the Mandelbrot thing, but I'd misremembered and it was a ray-tracer entered in the 1993 Obfuscated PostScript Contest.

(The same competition was won by a labyrinth generator, as it happens.)
Link Reply to this | Parent
[personal profile] bens_dadThu 2018-08-30 08:10
I have a vague memory of someone I know plotting a Mandelbrot set by means of sending a PS program to calculate it to the nearest printer.

At the time I came across one of those print jobs, the Apple LaserWriter (II?) had a faster processor than a Mac, so it was likely faster than generating the picture on a Mac then printing the result.

If you picked the wrong region it would tie up the printer for hours (modulo power-cycling IIRC).
Link Reply to this
navigation
[ go | Previous Entry | Next Entry ]
[ add | to Memories ]