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.
|