[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon Apr 21 10:02:25 1993 
Subject:Stack Citizenship 
From:Steve Knight 
Volume-ID:930421.01 

In a recent mailing, Aaron Sloman wrote:
> I suspect the open stack, which is such a nice feature when used without
> error is a FAR worse source of debugging and maintenance problems: they
> certainly hit me more often than problems about variable types. A
> symptom is that you can't use things like printf in their garbage-free
> format (printf(p1, p2, ..., <string>)) without risk of run time error,
> as I was recently reminded by Ian.

The topic of the open stack as a source of problems comes up with 
regularity.  And I do see stack-misuse problems in code about once
or twice a year -- enough to feature in my role-call of defects but
not enough to catch a headline.  It is my belief that this infrequency
of error is due to the excellent design of the language.  I would
contrast it with FORTH where stack errors are a very high proportion of
problems.

The ``garbage-free'' format of -printf-, which I would refer to as
its secondary format, is seriously flawed from a design viewpoint[*].
And it is important to design procedures that interact well with the open
stack policy.  

One principle that I call ``good stack citizenship'' is a cornerstone
of Pop's built-in protection against stack errors.  All of Pop's 
standard procedures are good stack citizens.  This means that they remove
*all* their arguments from the stack before they allow any other procedure
to run.  It is this principle that the idiom "dlocal cucharout = identfn;"
relies on, for example.

One way of illustrating good stack citizenship is to show a version of
a *bad* stack citizen.  Here's -applist- written as a bad stack citizen.
It will apply a procedure to each element of the list (usually).

	define applist( P ); ;;; don't do this at home, kids
	    until dup().null do
	        dest().swap.P
	    enduntil
	enddefine;

It is certainly cute.  It is also useless.  Idioms such as

	applist( 0, mynumbers, nonop + ) =>

crash and burn because the stack is being overused.  (But sometimes
you do write bad stack citizens deliberately -- a story for another
time, I guess.)

The open stack policy is what distinguishes Pop from Lisp and it is
through cunning design that the potential problems of this policy
are so infrequently seen.

Steve

[*]
Firstly, the implementation is incorrect.  It suffers from a defective
interaction with process copying.  (See the implementation of
-sys_print_object- in ObjectClass 5.08 for a solution.)  If the
printing is suspended between the allocation - deallocation points
of the internal list, arbitrary behaviour can result.  This incorrect
implementation stems from the complexity of writing ``garbage-free''
code in an environment with multiple continuations.

Secondly, the number of parameters taken by -printf- in this second
format are a function of the control string.  The compiler cannot 
perform any checking on your behalf as a result.  If -printf- was
redesigned as a syntax word then it would be possible to perform and
enforce checking.