This document has a standard, validated CSS2 stylesheet, which your browser does not seem to display properly. In a browser supporting web standards, this table of contents would be fixed at the side of the page for easy reference.
anastigmatix homePostScript programs can see themselves. As in languages like Scheme and ML, a procedure in PostScript is also data that can be examined, manipulated, or created on the fly by another procedure.
At first blush that may sound like esoteric hackery, but PostScript programmers already commonly use it in some simple ways. MetaPre subsumes those ad hoc techniques to give any PostScript interpreter a simple syntax for writing programs in stages. The name plays on other staged programming languages like MetaML, allowing that MetaPost was already taken by John Hobby's fine graphics language, and MetaPre works a bit like a preprocessor, anyway.
Here is a simple technique sometimes seen in existing PostScript programs.
A procedure may begin
a private dictionary in order to have
local named variables. If the procedure does not need to be reentrant,
there is no need to create a new dictionary on each call. The code below
creates a dictionary once and places it in the procedure:
/myproc { DUMMY begin /foo 42 store /bar 7 store foo bar add end } bind def /myproc load 0 << /foo 0 /bar 0 >> put
The last line replaces the placeholder DUMMY
, knowing it is index
zero in the array, with a private dictionary allocated only once in advance.
The technique is simple enough, but gets harder to read if replacing more than
one element, and you have to count to know the right indices, and count again
when something changes. It also won't work if array packing is enabled,
because a packed array can't be stored into.
If you were able to write something like:
/myproc { -|[ << /foo 0 /bar 0 >> ]|- begin /foo 42 store /bar 7 store foo bar add end } metabind def
you would have a language for
staged programming,
where ad hoc
messing with arrays has given way to a simple syntax for procedures with parts
that are filled in at different stages of execution. In this example, the hole
before the begin
is filled in with a dictionary allocated once at
the time the procedure is defined. Staged programming turns out to be an idea
made for PostScript: easy to implement because so much is already there (and
because PostScript has no static typing, which is where interesting
staged-programming
research issues lurk), and an elegant approach to some of the less elegant
corners in PostScript programming.
A traditional appeal for staged programming is to performance. Here is a
procedure Rot2
that takes two points and rotates them about the
origin by a given angle:
/Rot2 { % x0 y0 x1 y1 ang *rot2* x0' y0' x1' y1' matrix rotate 5 -2 roll 2 index transform 5 2 roll transform } bind def
What if there will be many pairs of points all to be rotated by an angle known
in advance? Rot2
recomputes the transformation matrix for each
pair of points. How about a procedure MakeRot2 that takes an angle
and returns a procedure that will rotate any pair of points by that
angle? Now the computation is staged: the matrix is computed at one stage when
we have the angle; the transformations are done in the next stage when we have
the points.
/MakeRot2 { % ang *MakeRot2* x0 y0 x1 y1 => x0' y0' x1' y1' { 4 2 roll -| matrix rotate [ 1 index ] |- transform 4 2 roll -|[ exch ]|- transform } } metabind def
For any angle ang, MakeRot2
will produce the following
procedure:
{ 4 2 roll M transform 4 2 roll M transform }
where M is the precomputed transformation matrix. Not only has the computation of the matrix been moved out of the procedure, but the stack manipulations are simpler: there is no need to keep track of M on the stack along with the four coordinate values, because M is simply wired into the procedure in the right places. PostScript is a language that puts unusual emphasis on stack manipulation, and this potential to keep the stack cleaner is, on top of the performance possibilities, one of the reasons staged programming is especially useful in PostScript. Staged code can be not only more efficient, but more readable.
As a hint for reading MakeRot2
, shift your eyes' focus to only
what you see between -|
and |-
, imagining a
consume at every |-
like this:
matrix rotate [ 1 index ] consume [ exch ] consume
All of that happens in the first stage, at the time MakeRot2
is
applied to the angle ang, where consume means an array on
top of the stack gets consumed—think pop
.
You can convince yourself it produced
two arrays, each containing a copy of M. The arrays got consumed by
splicing their contents into the procedure being generated, which is
everything you see when your eyes focus outside the
-|
and |-
:
{ 4 2 roll -|...|- transform 4 2 roll -|...|- transform }
If you think of the -|...|-
s as “holes” in the
procedure being generated, then what you see through the holes is a consistent
story of stack manipulations and computations going on at the time the
procedure is being built, and the rest—what you see with the
holes filled in—is the computation that will go on when the procedure
is used.
Interestingly, the language Forth, a much older and less sophisticated progenitor of PostScript, had a way to intermix compilation and interpretation states for a similar effect.
PostScript supports the distribution of reusable code in the form of
resources, which can be managed in an
extensible naming scheme using operators built into the language. A new
resource is distributed as a PostScript program that ultimately invokes
defineresource
to register its category and name, and is
well-behaved as set out in the language specification, leaving stacks
as it found them and having no effect on state other than memory consumption
and resource registration. MetaPre itself is distributed in this form.
A program that is a client of the resource can use findresource
to obtain a single object, often a dictionary containing the definitions the
resource makes available to the client. Unless the client pushes this
dictionary on the dictionary stack, there can be no clash between names
used in one resource and those used in another, or otherwise available to
the program. Such a separation of name spaces becomes especially important
in ambitious programs that may import many different resources.
If a resource uses many internal definitions that its procedures refer to by
name, its dictionary will be cluttered with many definitions of no use to the
client and possibly conflicting with other names in use, and the client will
be forced to have it on the dictionary stack in order for the resource's
procedures to work. Also, the resource's procedures may misbehave if names of
internal definitions they rely on match other definitions earlier on the
dictionary stack. If the resource is coded with internal references
pre-resolved, those name lookups are avoided. Speed is not the issue, because
PostScript name lookup is extremely fast, but the risks of name conflicts and
unforeseen interactions can be minimized this way. The client is then able to
use the resource's procedures by finding them with get
in the
dictionary returned by findresource
and exec
ing
them, without ever putting the dictionary on the lookup stack.
A resource may be loaded in global or persistent VM. If it offers settings
to be chosen by the client, they should not be made directly in the global
data structures—and possibly cannot be made there, if they involve
local objects allocated by the client, which cannot be stored in global
structures. One solution can be a staged design where the dictionary
returned by findresource
contains only a single procedure the
client will call to generate a fresh local dictionary containing
procedures specialized to the client's settings. The design can be
space-efficient because the generated, exported procedures are only stubs
made mostly of pre-resolved references to global, internal definitions.
A good introduction to the concepts and benefits of staged programming (notwithstanding some typos) is Tim Sheard's paper, Using MetaML. It introduces three fundamental concepts in a staged language:
5-cbrt(27)
performs a function call and a subtraction and
produces 2, the source text <5-cbrt(27)>
produces a
fragment of program code that will, if run, perform a call and a subtraction
and produce 2. And the text <<5-cbrt(27)>>
produces
a fragment of code that, when run, will produce that fragment, which, when
run, will produce 2.<5-~cbrt(27)>
executes cbrt
immediately,
obtaining 3, and produces delayed code that will subtract 3 from 5 when run,
producing 2. The result of an escaped expression, however, can be code of any
length, which is spliced at the proper point into the code being generated.
To add staging to languages that have static typing involves challenging research questions: how to guarantee that a well-typed program at one stage generates a well-typed program for the next? Because PostScript is only dynamically typed, it can be staged on the cheap; the hard questions are left to the statically typed languages. And the natural affinity of PostScript for staged programming lies in that bracket and run are already in the language! Only an escape notation needs to be supplied.
PostScript's curly brackets are exactly the delay notation needed for a staged programming language. This may not be obvious at first glance, because many programmers accustomed to languages like Java write and format PostScript strictly as if the brackets were no different from compound statement notation in those other languages, and the programs work, which seems to confirm the idea:
foo bar eq { if ( foo == bar ) { doSomething doSomething } { } else { doSomethingElse doSomethingElse } ifelse }
That impression can be shaken loose by doing something in PostScript you'll never see in Java:
{ doSomethingElse } foo bar eq { doSomething } 3 -1 roll ifelse
In that example it is easy to see that ifelse
is simply an
operator that takes three values on the stack, and two of those values are
delayed code. It discards one, and executes the other. Another way to see
the point, if it needs reinforcement, is to see the curly brackets in the
Java example are unnecessary: meaning does not change when Java brackets
are put around doSomething
to make a compound statement of it.
Meaning does change in PostScript from doSomething
to
{ doSomething }
: the first will do something, but the second
will push a piece of code on the stack to do something later.
Once it is clear that PostScript curly brackets are exactly delay brackets, another interesting fact falls out: PostScript has no syntax for grouping except for delay brackets. As a consequence, PostScript programs have many uses of delay brackets that have nothing to do with deliberate staging, just because they are the only way to write a simple conditional or loop, and that motivates some extra flexibility you will see in MetaPre's escape notation.
PostScript also has the operator corresponding to run. It is, of
course, exec
, with exactly the effect its code argument would
have with one outer pair of delay brackets eliminated. Of course there are
many other operators in PostScript that have the effect of exec
as part of what they do, starting with all the conditionals and loops, but
exec
is the operator that purely undoes the effect of delay
brackets and is the exact counterpart of run.
The piece that completes the staged programming environment is the escape
notation, and this is the piece that MetaPre provides. Within a bracketed
code sequence, any code between -|
and |-
is
not delayed. When exactly is the escaped code executed? The best
answer, and only slightly oversimplified, is exactly when the bracketed
code immediately containing it is pushed on the stack:
{ (Pushed: ) print -| (hi!) = [realtime] |- = (Executed: ) print realtime = }
When PostScript encounters the procedure above, the effect will be to push it
on the stack. At that time, the escaped sequence (hi!) =
[realtime]
is executed, printing hi!
and producing an
array. The array's contents—a single integer—will be spliced into
the procedure being pushed. The procedure as it actually winds up on the stack
looks like this:
{ (Pushed: ) print R = (Executed: ) print realtime = }
where R is the time the procedure was pushed. If it is then
exec
'd at some later time, it will print:
Pushed: R Executed: X
where X is the time of execution.
What happens if more delay brackets are present?
{ -|[realtime]|- { (Inner pushed: ) = -|[realtime]|- = (Outer pushed: ) = = (Executed: ) print realtime = } }
The interpreter will push this code on the stack, executing the first escaped sequence as before. The second escaped sequence is not yet executed, because the bracketed code immediately containing it is not being pushed yet. The stack now contains (where Q is the current time):
{ Q { (Inner pushed: ) = -|[realtime]|- = (Outer pushed: ) = = (Executed: ) print realtime = } }
Following one exec
, the stack will contain (where R is
the time of that exec
):
Q { (Inner pushed: ) = R = (Outer pushed: ) = = (Executed: ) print realtime = }
Another exec
will produce the output:
Inner pushed: R Outer pushed: Q Executed: X
Here is another route to the same output:
{ { (Inner pushed: ) = -|[realtime]|- = (Outer pushed: ) = -1|[realtime]|- = (Executed: ) print realtime = } }
Here both escapes are contained in the inner, nested bracketed code, but they are substituted at different times. Corresponding to the depth of bracket nesting, each escape has a height. The first escape above has height zero and, just as before, it is not executed until its immediately containing bracketed code is pushed on the stack. But the escape with height one is executed at the time its next outer containing code is pushed. So, when the interpreter first pushes the procedure above, what gets pushed is:
{ { (Inner pushed: ) = -|[realtime]|- = (Outer pushed: ) = Q = (Executed: ) print realtime = } }
After one exec
, the stack contains:
{ (Inner pushed: ) = R = (Outer pushed: ) = Q = (Executed: ) print realtime = }
One more exec
produces output matching the earlier example.
The notation for escape height is important in PostScript because the
structure of the language requires delay brackets for non-staging
purposes like conditionals and loops, so that many places in the same
procedure where you might want to place escapes will actually be at different
depths of delay nesting:
{ -| (The ) [] |- rand 16#3fffffff le { -1| (same ) [] |- 1 { -2| exch print print (stage.) = [] |- } repeat } if }
The stage at which each escape will be executed is the depth of enclosing delay brackets minus the escape's height; all of the escapes in the above code are executed at the same stage. A consistent indentation scheme for curly brackets can simplify getting the escape heights right.
The example also shows information propagated from one escaped sequence to another on the stack. Each escaped sequence is expected to leave an array on top of the stack, containing the code to splice into the procedure being generated, and that array will be consumed, but other stack effects are unrestricted. Escaped sequences at the same stage are executed in a left-to-right, depth-first traversal; the leftmost sees the stack on which the procedure under construction was to be pushed, and each leaves the stack as the next will see it.
The rule of thumb that escapes (of height zero) are expanded at the moment their
immediately-containing bracketed code is pushed on the stack is conceptually
right, but missing one practical detail. MetaPre does not actually hook
PostScript's scanner to process procedures as they are scanned and placed
on the stack. Instead, a procedure that contains escapes (at any depth of
nesting) must be followed by metapre
:
{ { (Inner pushed: ) = -|[realtime]|- = (Outer pushed: ) = -1|[realtime]|- = (Executed: ) print realtime = } } metapre
In reality, then, PostScript's scanner first pushes the procedure on the stack
just as it was read in—to the scanner, MetaPre's escape delimiters are
merely names—and then metapre
, like the operator
bind
, leaves the preprocessed version on the stack in its place.
As with bind
, only one metapre
is needed after the outermost closing bracket; it makes the necessary
arrangements for any nested code with later-stage escapes to be expanded
later when pushed on the stack. Because bind
and
metapre
will often be applied together at the end of a procedure
body, as a convenience metabind
does both.
MetaPre is a ProcSet resource. To make it available to your own code, include in the setup section of your file:
/net.anastigmatix.MetaPre /ProcSet findresource begin
The findresource
will succeed if you have made
the
MetaPre
resource file [download]
available in any of these ways:
findresource
(which belongs in the
setup section)%%DocumentNeededResources
and
%%IncludeResource
DSC comments, you include these comments at
the right position in your file to specify that it needs
net.anastigmatix.MetaPre, your document manager software is configured to
automatically insert needed resources in files being printed, and you have
put the MetaPre resource file where your document manager can find
it.The resource file is in a compact form. That is for efficiency, not to keep you from viewing it; there is a script for that on the resource packaging page.
The MetaPre dictionary is read-only. Before creating any definitions, you
will want eitheruserdict begin
or your own dict
begin
so that you have a writable dictionary on top of the
dictionary stack.
If the code you are writing will itself be distributed as a resource, be sure
to finish with the right number of end
s to leave the dictionary
stack as it was before MetaPre and your own dictionary were put on it. Also
consider using immediately-evaluated names to refer to MetaPre definitions
inside of procedures you create: instead of /foo { 3 hide } def
,
you would write /foo { 3 //hide exec } def
. This will allow your
code to work whether or not the MetaPre dictionary is on the lookup stack at
run time. This applies only to references to MetaPre definitions
inside your procedures; there is no point in doing anything special
with metapre
or metabind
(or anything else) used
outside brackets, or to the -|
, -n|
, and
|-
escape delimiters in your procedures.
Scans proc left to right, applying itself recursively to nested procedure objects (depth first), looking for escaped sequences, that is, sequences of code delimited on the left by an executable name -| or -h| where h is a positive integer and -| is equivalent to -0|, and on the right by the executable name |-. metapre immediately executes, in the current environment, every escaped sequence whose height h equals its depth in procedure nesting, where proc itself is at depth 0. Each escaped sequence is expected to leave an array result on top of the stack, which is consumed and whose contents are spliced into the containing procedure in place of the escaped sequence and its delimiters. The code just spliced is then scanned itself as if it had been newly pushed at depth 0. proc is removed from the stack while escaped sequences are executed, and the stack is otherwise left alone, so the first escaped sequence sees the stack as it was when metapre was invoked (but with proc removed), and each subsequent sequence sees the stack left by the prior one (but with the array result consumed).
For every escaped sequence found with height h less than its depth, metapre finds the hth enclosing procedure p and the procedure q enclosing p, and inserts a resolved reference to metapre into q immediately following p, so that when p is later pushed on the stack, metapre will process it and expand the escaped sequences intended for that stage. The resolved reference to metapre is made execute-only as a convenience, so procedures incorporating metapre can be usefully printed with == without getting lost in metapre itself. When metapre inserts a metapre reference after a procedure p, the p reference is made literal, so that intervening metapre passes will not unnecessarily recurse into it. At the time p is pushed on the stack, the following metapre will make it executable again.
Because metapre may be invoked on packed or read-only arrays, and the expansion of escaped sequences is likely to change lengths, it is not safe to assume that proc' is the same array as proc, or to make that assumption for any recursively contained procedure, unless it and its descendants contain no escapes.
Because bind and metapre will commonly both be applied to new procedures as they are defined, as a convenience metabind is equivalent to bind metapre.
It is often useful to be able to execute some code with certain values removed from the operand stack, and recover them later. Sometimes it simplifies a bit of stack manipulation that needs to be done, and sometimes robustness dictates that a user callback or other procedure of unknown quality should be called with a stack clean of any values it does not need so the damage will be contained if its stack management is a little off. metapre removes its mess temporarily from the stack when executing escaped code sequences, so the programmer can remember a simple rule about what those sequences will see on the stack. The same capability is made available to other code, in six flavors:
Executes proc with the n top values anyn-1...any0 popped from the stack. On completion of proc, which may have consumed and added other values on the stack, hide restores the n temporarily hidden values as an n-element array on the top of stack. Restoring them in array form simplifies access to any results from proc below the array, or a simple aload pop will restore the hidden elements to their rightful individual places atop the stack.
hide is built on hide+k by supplying the continuation {exch{stop}if}.
As hide followed by aload pop, so the n hidden items are replaced on the stack as individual items rather than an n-element array.
hide+ap is built on hide+k by supplying the continuation {exch{stop}if aload pop}.
Executes proc with the n top values anyn-1...any0 popped from the stack, then executes k with whatever was left on the stack by proc, one boolean (true if proc encountered a stop, false otherwise), and an n-element array containing the values removed before executing proc.
Sometimes the things you want visible to proc are on top of the stack, and the things you want to hide are below them. Hides the h items anyv+h-1...anyv, executes proc and then replaces the h hidden items on top of its result as an h-element array, like hide.
As hvhide followed by aload pop, so the h hidden items are replaced as h individual items on the top of stack rather than an h-element array.
Executes proc with the h top items anyv+h-1...anyv popped from the stack, then executes k with whatever was left on the stack by proc, one boolean (true if proc encountered a stop, false otherwise), and an h-element array containing the values removed before executing proc.
In PostScript's no-nonsense ancestor Forth, you could get things temporarily off the operand stack by shuffling them onto the return stack, but the crashes could be spectacular if you forgot to shuffle them back. These procedures offer a more robust, if less exhilarating, way to get the same effect in PostScript.
The language Forth, also stack-based and postfix, did manage to have a readable structured IF/ELSE construct, achieved with Forth's version of staged programming; the IF, THEN, and ELSE words accumulated information on the stack during parsing, then used it to generate a final procedure with the corresponding control flow. A staging environment for PostScript ought to be able to use similar techniques. MetaPre provides a control flow construct using the words if:, else:if, else:, :if, and short-circuiting boolean connectives :and and :or.
-| if: condition condition : proc (with boolean result) proc | condition condition :and else:if condition | condition condition :or proc ; else: proc :if |-
As in any familiar if-construct, the else:if part can occur zero or more times, the else: part can be present or absent, and nested instances of the structure can be present. The source of MetaPre itself contains a fairly elaborate example, which I would not have enjoyed writing using plain PostScript if and ifelse with all the parallel cases getting ever more buried in brackets. A new if-construct may be syntactic sugar, but sometimes a little sugar makes a big difference.
The construct must appear in an escape as shown (with the proper height for its context, not necessarily as shown) because it generates code. if:, else:if, and else: put things on the stack, interleaved with the conditions and procs, and :if consumes them all and generates a procedure out of PostScript operators (the usual form, ever more buried in brackets) to be spliced in for the escape.
Similarly, :and and :or are not connectives that take two boolean values and produce a boolean result; they are connectives that take two procedures embodying boolean tests, and generate a procedure combining both tests in left-to-right, short-circuit fashion.
In infix languages, the short-circuiting && and || operators usually have different precedence, with && binding more strongly, and parentheses are available to adjust the default. The usual translation from infix to postfix works to match any such expression with :and and :or and no parentheses:
Infix | Tree | Postfix |
---|---|---|
a && b || c |
|| && c a b |
{a}{b}:and {c}:or |
a && ( b || c ) |
&& a || b c |
{a}{b}{c}:or :and |
Think of the position of your :ands and :ors as determining
the shape of an expression tree, not as determining which
operator is evaluated first. The generated code will always do a
left-to-right, short-circuit evaluation; in both trees above,
{a}
is the first leaf condition
tested—by :and
—but in the second form, if you
were stuck thinking evaluation order instead of tree shape, you might
mistakenly expect {b}{c}:or
to be evaluated first.
While you are building an if: construct—before the final
:if—the stack contents can be reasoned about. The :if and
each else:if adds an item, each condition and proc is an
item, so there are three items for each branch. else: has no
condition, but adds two items rather than one so the invariant is
preserved. If you have a complicated series of tests that do not factor easily
so every proc is unique, in place of a proc you can use 2
index
to share the proc from the previous branch, 5
index
for the branch before that, and so on. Sharing reduces duplicated
code and the risk that maintenance overlooks some copies. Be advised that if
you do this with a proc that contains escapes, it will wind up
referenced in two places with different nesting depths, and I am not sure
what MetaPre will do but it's probably not what you want.
A variation of forall that, instead of executing a fixed proc each iteration, executes the proc found on top of the stack before pushing each iteration's value(s). The proc must leave itself, or another proc, on top of the stack for the next iteration. xforall pops it on completion.
In other words, xforall is equivalent to
{exch exec} forall pop
except when applied to a dictionary,
in which case it is {3 -1 roll exec} forall pop
. This design
pattern is simple enough to code using plain forall, but with
xforall it's a little clearer. It can be used (with
ingroups, for example) to apply a proc to each group of
n items from an array or string, to write a loop with special
behavior for the first iteration(s), or in implementing a state machine.
Construct procint as would be used with xforall to apply proc once every intth iteration. That is, proc1 is equivalent to proc but leaves procint on top of the stack, and prock for every k > 1 simply leaves prock−1 on top of the stack, disturbing nothing else. When used with xforall then, items pushed from the array, dictionary, or string accumulate undisturbed on the stack so that proc can find the values from int iterations on the stack as a group.
As an example, with int = 4
,
procint is effectively
{{{{proc //procint}}}}
, without the name lookups.
Again, it's a design pattern that's not too hard to code explicitly, but
ingroups looks a little nicer.
This example will treat myarray, with even length, as consecutive pairs of numbers and print the sum of each pair:
myarray {add =} 2 ingroups xforall
However, because ingroups does some allocation, if this code will be used more than once it is more efficient to do the ingroups in advance:
/addbypairs {add =} bind 2 ingroups def myarray //addbypairs xforall
Note that bind, metapre, or metabind, if needed, should be applied to the procedure before ingroups.
The need to put explicit escape delimiters around this if construct is an annoyance. In Forth, IF is an immediate word, which effects an automatic switch from delaying to evaluating code, and MetaPre should one day have that ability also.
This if-construct is syntactic sugar for the usual PostScript if/ifelse form, where later branches are at increasing depth of delay nesting. When placing escapes in such deeply nested code, it can be a challenge to get the heights right, and it is even more of a challenge with this construct, which conceals the nest of brackets from view. Ultimately, MetaPre should understand some form of “virtual” depth correction, which the if-construct could place automatically in the code that it generates so that MetaPre's understanding of nesting depth matches what appears in the source. That is not likely to require many lines of code—they just have to be the right ones, and they are not there yet.
MetaPre supplies a few procedures that have little to do with staged programming, but are useful for developing modular and reusable PostScript resources, one of the reasons for developing MetaPre, and they had to go somewhere. The queue procedures are just there because MetaPre needed them and they might as well be exported to save the trouble again.
Dequeue an item from a singly-linked queue. queue is an array expected to have, at index 0, null if the queue is empty, or the tail item in the queue. Each item is an array whose last element is the next item (but for the tail, whose last element is the head). If the queue is not empty, the head element is removed and returned, with the flag true. If the queue is empty, only the flag false is returned.
The element returned is shortened (with getinterval) so that it does not include the former last element (queue link).
Enqueue an item on a singly-linked queue. queue is an array expected to have, at index 0, null if the queue is empty, or the tail item in the queue. new is an array that is to be the next item in the queue. enq updates queue and the tail of the queue, as necessary, but does not update new. head is the value that should be stored in new's last element to complete the insertion; the stack order is convenient if the caller will finish populating new with an astore.
Initiate the handling of error name. If name is an error known in errordict, fetch and execute the associated value with any on top of the stack, just as an error detected by the interpreter is handled.
If name is not known in errordict, do what the default handlers in errordict do: save name as the errorname and any as the command in $error, record the stacks, set local allocation mode, and execute stop. errorstop makes it simple for modular resources to signal their own specific exceptions, as it is not necessary to enter anything in errordict first, though an entry can still be made in errordict to alter the handling of the error.
Create a new dictionary exactly the size of namearray, and copy into it only the names in namearray and their values as found on the current dictionary stack by load. Remove the top dictionary on the dictionary stack and discard it, and leave the new dictionary, containing only the exported definitions, on the operand stack.
These are common operations for a reusable module packaged as a resource, as MetaPre itself is. The dictionary on top of the lookup stack is assumed to be the private one used in the resource-defining file, containing both the definitions meant to be visible and any number of internal implementation factors. The procedures are assumed to contain bound references to each other rather than relying on name lookup, so it is now safe to discard the dictionary with the names of internal factors. The dictionary returned, containing just the definitions to be exported, is ready to register with defineresource.
To write a recursive procedure that will not need to look up its name at run time, simply write it as if you expect one extra operand, a procedure, on top of the stack. At a recursive call point, exec that procedure. Although you are writing as if you expect the extra object on the stack, do not pass anything extra when you exec it (i.e., do not write dup exec). Assume its stack effect is exactly that of the procedure you originally wanted to write.
After writing the procedure that way, just apply fix to it to get the procedure you wanted to write. (The name comes from the slightly esoteric fact that the procedure you want is a “fixed point” of the procedure you write.) Everybody uses factorial as the example, so here goes:
/f { 1 index 0 eq {pop pop 1} {1 index 1 sub exch exec mul} ifelse } bind fix def 7 f = 5040
Notice that if other procedures using f use bound references to it, the dictionary with its name can be safely discarded; in fact, there was no need to name it at all.
If you use bind, metapre, or metabind on your procedure, they go before fix.