[comp.lang.postscript] Defining procedures with named parameters

amanda@mermaid.intercon.com (Amanda Walker) (03/01/90)

I've been thinking about ways to define PostScript procedures with named
parameters.  The syntax would be something like:

/mumble [/foo /bar/zot] {
	...
} procdef

where "foo," "bar," and "zot" would be bound to the parameters passed on
the stack during the execution of the body of the procedure.  It's fairly
easy to make a quick-and-dirty version of this that makes a little private
dictionary for this procedure in which it can define the names, but
this approach has a couple problems:

 - it amounts to dynamic binding if you just go "<dict> begin" at the beginning
   and "end" before exiting, which means you can get weird side effects.

 - if the dictionary is allocated statically at the time that the procedure
   is defined, "mumble" can't call itself except tail-recursively, since
   the caller's copy of the arguments gets overwritten by the callee.

 - if the dictionary is allocated on the fly, we avoid the above problem,
   but each invocation of "mumble" consumes an amount of VM proportional
   to the number of arguments.  This is OK under NeWS, where the orhpaned
   dictionary will get garbage-collected away, but it would be bad in a
   printer or other PostScript implementations with the standard Adobe
   memory model.

Another approach would be to walk through the procedure and substitute each
occurence of a parameter with code to pull it off of the stack with "index."
This has the advantages of lexical binding, no recursion problems, and no
net VM usage, but it does mean that "procdef" would have to know how every
possible operator affects the stack so that it can track the runtime stack
height as it walks through the procedure.  This could be difficult...

Has anyone out there implemented anything like this, or do you have any
inspirations for better approaches?

--
Amanda Walker
InterCon Systems Corporation

"Many of the truths we cling to depend greatly upon our own point of view."
	--Obi-Wan Kenobi in "Return of the Jedi"

hemphill@cit-vax.Caltech.Edu (Scott Hemphill) (03/01/90)

In article <1990Feb28.192129.9580@intercon.com> amanda@mermaid.intercon.com (Amanda Walker) writes:
>I've been thinking about ways to define PostScript procedures with named
>parameters.  The syntax would be something like:
>
>/mumble [/foo /bar/zot] {
>	...
>} procdef
>
>where "foo," "bar," and "zot" would be bound to the parameters passed on
>the stack during the execution of the body of the procedure.  It's fairly
>easy to make a quick-and-dirty version of this that makes a little private
>dictionary for this procedure in which it can define the names, but
>this approach has a couple problems:
>
> - it amounts to dynamic binding if you just go "<dict> begin" at the beginning
>   and "end" before exiting, which means you can get weird side effects.
>
> - if the dictionary is allocated statically at the time that the procedure
>   is defined, "mumble" can't call itself except tail-recursively, since
>   the caller's copy of the arguments gets overwritten by the callee.
>
> - if the dictionary is allocated on the fly, we avoid the above problem,
>   but each invocation of "mumble" consumes an amount of VM proportional
>   to the number of arguments.  This is OK under NeWS, where the orhpaned
>   dictionary will get garbage-collected away, but it would be bad in a
>   printer or other PostScript implementations with the standard Adobe
>   memory model.
>
>Another approach would be to walk through the procedure and substitute each
>occurence of a parameter with code to pull it off of the stack with "index."
>This has the advantages of lexical binding, no recursion problems, and no
>net VM usage, but it does mean that "procdef" would have to know how every
>possible operator affects the stack so that it can track the runtime stack
>height as it walks through the procedure.  This could be difficult...
>
>Has anyone out there implemented anything like this, or do you have any
>inspirations for better approaches?
>
>--
>Amanda Walker
>InterCon Systems Corporation

First, a thought on the last approach.  It isn't necessary to know so much
about how various operators affect the stack.  All that is required is to put
a mark on the stack which identifies where the parameters are.  Oh, I don't
mean a *real* mark (i.e. "-mark-").  A literal name such as "/procmark" which
has no other purpose would do the trick.  You could then write your own
"counttoprocmark" and calculate the appropriate stack index.  All this seems
a little messy, though.

The dynamically allocated dictionary works well, as you have said, but the
VM usage is a problem.  So the statically allocated dictionary seems
attractive, as long as we can fix the problem of variables being clobbered by
recursive calls.

The natural thing to do would be to save the old variable contents on the stack
before assigning the new ones.  The trick described above using "/procmark"
is useful for this.  Thus, the procedure being defined could be
encased something like this:

% This is the definition of mumble
  {
    <dictionary> begin
    /procmark                    % new-vars /procmark
    foo bar zot                  % new-vars /procmark old-vars
    7 3 rot                      % /procmark old-vars new-vars
    /zot exch def
    /bar exch def
    /foo exch def                % /procmark old-vars
    <procedure> exec             % /procmark old-vars possible-new-stuff
    counttoprocmark 1 add 4 rot  % possible-new-stuff /procmark old-vars
    /zot exch def
    /bar exch def
    /foo exch def                % possible-new-stuff /procmark
    pop                          % possible-new-stuff
    end
  }

This method involves extra overhead when non-recursive procedures are defined,
and could potentially eat up a lot of stack.  So you could have two different
ways to define procedures, such as "procdef" and "recursiveprocdef".
-- 
Scott Hemphill	hemphill@csvax.caltech.edu	...!ames!elroy!cit-vax!hemphill

amanda@mermaid.intercon.com (Amanda Walker) (03/02/90)

In article <14040@cit-vax.Caltech.Edu>, hemphill@cit-vax.Caltech.Edu (Scott
Hemphill) writes:
> The natural thing to do would be to save the old variable contents on the
> stack before assigning the new ones.

I knew I was forgetting some simple approach.  Grin.  I've been using deep
binding in Lisp & PostScript for so long that I forgot about trying shallow
binding...  It still has the potential side effect problem, but at least
it should work and is quite simple.

If you restrict such procedures to returning single objects on the stack
(or, even better yet, leaving the number of returned values on the top of the
stack for the postlog code to look at), you don't even have to mess with
the "counttoprocmark" stuff, which should be a speed win.  Also, this way,
it wouldn't take any more stack space than leaving the parameters on the
stack would.

Off to write some code...

--
Amanda Walker
InterCon Systems Corporation

"Many of the truths we cling to depend greatly upon our own point of view."
	--Obi-Wan Kenobi in "Return of the Jedi"