Reputation: 1673
I've been coding in PostScript for a couple of months, and I'm wondering how one would implement namespaces, and use libraries.
As usual, the idea is to address:
I've come up a first sketch of what that might look like for me. The case I'm most interested in is that of defining a library for general use, and how, as a consumer of such a library, I would like to interact with its procs.
Below are two short experiments for an imaginary 'charting' library. Both code examples execute without error.
Q1: Do the code snippets below have a reasonable design? Is one to be preferred over the other?
Q2: The docs speak of NamedResources and ProcSets. Should those be used instead, for implementing libraries?
Experiment number 1:
%!PS-Adobe-3.0
% Experiment for defining a namespace in PostScript.
/pg-wd 720 def
/pg-ht 720 def
<</PageSize [pg-wd pg-ht]>> setpagedevice
/Times-Roman 15 selectfont
% PICTURE THIS AS BEING IN A SEPARATE FILE, AND BEING INCLUDED into your
% program with a 'run' OR 'runlibfile' (Ghostscript).
%
% At the top level, the library defines only 1 proc.
% Let's call this the INSTALLATION PROC.
% It returns a dict with various procs for making charts.
/some-glorious-charting-library-dict {
% push a temporary dict on top of the dict-stack, as a working area
2 dict begin
% pass in a data-dict to each charting proc
/pie {
(Making a pie-chart...)==
0 0 moveto
(title)get show
} def
% pass in a data-dict
/bar {
(Making a bar-chart...)==
0 0 moveto
(title)get show
} def
% push a duplicate of this temp dict onto the operand stack
currentdict
% pop this temp dict from the dict-stack, so its left only on the operand stack
end
% STRANGE AND WEIRD: when executed, this proc deletes itself from userdict!
% There's no need to keep it around, since it's done its job.
currentdict /some-glorious-charting-library-dict undef
} def
% At this point, there's an entry named /some-glorious-charting-library-dict in userdict.
currentdict /some-glorious-charting-library-dict known == % true
% "INSTALL" the library in userdict.
% Use a long name for two reasons:
% - to avoid name collisions
% - to encourage you to define a "convenience proc" (see below)
(installed-library-for-charts) some-glorious-charting-library-dict def
% At this point, the entry named /some-glorious-charting-library-dict has been deleted:
currentdict /some-glorious-charting-library-dict known == % false
currentdict (installed-library-for-charts) known == % true
% Define a proc to allow curt access to the charting procs.
% Let's call this a CONVENIENCE PROC.
% This helper proc hides several things:
% - the long name
% - the three operators needed to access the proc (exch, get, exec).
% data-dict chart-proc-name
/chart {
installed-library-for-charts exch get exec
} def
% draw a pie chart
gsave
10 100 translate
<< (title) (I am ten leagues deep in calamity.) >> % a data-dict needed by the pie proc
(pie) chart
grestore
% draw a bar chart
gsave
10 200 translate
% You can identify the proc with either a string literal '(bar)' or a name literal '/bar'.
<< (title) (Of things that move not, I am the Himalayas.) >>
/bar chart
grestore
10 10 moveto
(Done) show
showpage
Also: it's likely a good idea for the consumer of the library to make it readonly
during the "installation" step, such that the library-procs can't be overwritten:
(installed-library-for-charts) some-glorious-charting-library-dict readonly def
Experiment number 2:
%!PS-Adobe-3.0
% The dictionary stack IS the namespace.
%
% As long as you're aware of the name-shadowing that can
% occur, this is the simplest implementation.
% I'm not sure, but this style may be more in agreement
% with the original intent of the language designers.
/pg-wd 720 def
/pg-ht 720 def
<</PageSize [pg-wd pg-ht]>> setpagedevice
/Times-Roman 15 selectfont
% PICTURE THIS AS BEING IN A SEPARATE FILE, AND BEING INCLUDED into your
% program with a 'run' OR 'runlibfile' (Ghostscript).
%
% At the top level, the library defines only 1 proc.
% Let's call this the INSTALLATION PROC.
% It returns a dict with various procs for making charts.
/some-glorious-charting-library-dict {
% push a temporary dict on top of the dict-stack, as a working area
2 dict begin
% pass in a data-dict to each charting proc
/pie-chart {
(Making a pie-chart...)==
0 0 moveto
(title)get show
} def
% pass in a data-dict
/bar-chart {
(Making a bar-chart...)==
0 0 moveto
(title)get show
} def
% push a duplicate of this temp dict onto the operand stack
currentdict
% pop this temp dict from the dict-stack,
% so its left only on the operand stack
end
} def
% Just add the chart lib temporarily to the current
% namespace (that is, to the dictionary stack).
% WARNING: a name in the library will shadow the same name in userdict.
some-glorious-charting-library-dict begin
gsave
10 100 translate
<< (title) (Hocus Pocus.) >> pie-chart
grestore
end
% you can choose to make the library proc's unwriteable:
some-glorious-charting-library-dict readonly begin
gsave
10 200 translate
<< (title) (Abracadabra.) >> bar-chart
%/bar-chart {0 0 moveto} store % this fails: readonly
grestore
end
% The same scheme could be used to reference multiple libraries at once,
% by nesting begin-end pairs.
showpage
Upvotes: 2
Views: 35