ray@philmtl.philips.ca (Ray Dunn) writes:
> Date: 26 Jan 93 03:39:34 GMT
> Organization: Not Philips.
>
> In refd article, axs@cs.bham.ac.uk (Aaron Sloman) writes:
[AS]
> >A really "clean" implementation would have required all local
> >variables to have their values initialised to some safe default on
> >procedure entry, e.g. to "undef".
[RD]
> ...and to take advantage of internal knowledge of the fact that it doesn't
> raises the hackles of anyone concerned about "future release surprise" or
> portability!
[AS]
But note that this has been a dependable feature of every Pop
implementation for at least 22 years. Suppose it were written into
the manual, would you still object to its use?
In fact, I think that it is an essential part of the dlocal
mechanism that you can access the previous value as well as being
able to update it. E.g. you can do things like
dlocal hd(list);
hd(list) + 1 -> hd(list);
in a procedure, with a *guarantee* that on exit from that procedure,
whether normal or abnormal, the previous value stored in the head of
the list will be reset. It would be illogical to disallow the
special case of a value stored in a variable.
Of course a defender of pure functional programming would disallow
the updating of a datastructure in any case, and the argument would
change (which is I think Robin's position, if I've understood it.)
Ray objected to my example use of this facility:
[AS]
> > define print_procedure( ..... );
> > dlocal printlevel = printlevel + 1;
>
[RD]
> looks pretty bogus to me. I've been trying to teach programmers to avoid
> this sort of thing for years. POP-2 was quite clear about it, even though
> this code would "work". The reference manual states that when the extent
> of another variable is interrupted "its value is not altered but it cannot
> be accessed or changed by assignment."
[AS]
Well, what I am claiming (if I understand the terminology correctly)
is that allowing the value from the previous context to be accessed,
but not altered, before the first assignment in the new context, is
a very useful extension to the expressive power of the language.
[AS]
>The alternative to these dynamically scoped uses of printlevel and
> >popmatchvars (and similar things, like interrupt, cucharout,
> >prmishap, etc.) would have been to require all these values to be
> >passed explicitly as extra arguments in any procedure that might
> >call a procedure that used these values, ....
> > .....
Which is what Ray recommends:
[RD]
> In 'C' the effect can often be achieved by using a _static_ variable, but
> my own technique is to use a pair of functions - the outer function
> presents a "clean" interface to the outside world and calls a second
> function with all the required extra arguments - it is this second function
> that recurses.
>
> So Aaron's example becomes (ha! I'll do it in POP-2ish)
>
> vars max_printlevel;
> 5 -> max_printlevel;
>
> print_procedure(....)
> aux_print_proc(..... , 1);
> end
>
> aux_print_proc(..... , printlevel)
>
> if printlevel >= max_printlevel then
> ... print closing bracket and return ....
> else
> ... print suitable opening bracket ....
> aux_print_proc(whatever tail of structure, printlevel+1);
> close
> end
Note that this solution works if all printing is done via one
procedure, which used to be the case in POP2, but is no longer the
case in Pop-11, where different data-types have their own
class_print procedures, a bit like an object oriented system where
each class has its own methods (as is the case in Steve Knight's new
objectclass extension to Pop-11) (advertisement).
Extracts from REF PRINT in the online manual follow:
-------------------------------------------------------------------
The basic printing procedure in POPLOG is -sys_syspr-, which prints any
item in its standard format. While this can be called directly if so
desired, the system additionally provides the procedures -pr- and
-syspr- as a two-stage mechanism for printing objects in a way that
allows dynamic redefinition of the actual printing procedures used.
The mechanism is based on the convention that programs normally
print objects using the variable procedure -pr-, which in the first
place, can be redefined in any desired way. However, the default value
of the variable -pr- is the procedure -syspr-, which prints an object by
calling its -class_print- procedure with the object as argument (see REF
*KEYS); thus in the second place, the printing of individual data types
can be altered by redefining their -class_print- procedures. Because the
default -class_print- of any type is -sys_syspr-, (printing in standard
format), the normal sequence of events is therefore:
pr(ITEM)
---> syspr(ITEM)
---> class_print(datakey(ITEM))(ITEM)
---> sys_syspr(ITEM)
It is important to note, however, that to enable the redefinition of
printing procedures for given data types to take effect at any level,
-sys_syspr- always calls -pr- to print the sub-components of any data
structure (i.e. list, vector and record elements, etc). (Thus saying
that -sys_syspr- 'prints any item in its standard format' is not
strictly correct, since the printing of sub-components will depend on
-pr-. A COMPLETELY standard printing procedure would be
define pr_standard(ITEM)
lvars ITEM;
dlocal pr = sys_syspr;
sys_syspr(ITEM)
enddefine;
i.e. one that locally redefines -pr- to be -sys_syspr-.)
pr(ITEM) [procedure variable]
This variable procedure is conventionally used by all procedures
in the system which print something; its default value is
-syspr-.
syspr(ITEM) [procedure]
This procedure does
class_print(datakey(ITEM))(ITEM)
i.e. apply the -class_print- of the data type of ITEM to ITEM.
The default -class_print- of every data type is -sys_syspr-, but
this can be redefined as desired -- see REF *KEYS.
-------------------------------------------------------------------
This means that for Ray's mechanism to work, every class_print
procedure would have to take an extra argument, namely the
printlevel, and every other procedure that did any printing would
have to be given a printlevel as part of its input, and then it
would pass on the incremented value to the next printing function it
called. So the above definitions would have to replaced with
something like:
pr(ITEM,INTEGER)
This variable procedure is conventionally used by all procedures
in the system which print something; its default value is
-syspr-.
syspr(ITEM,INTEGER)
This procedure does
class_print(datakey(ITEM))(ITEM,INTEGER)
unless INTEGER exceeds max_printlevel
I.e. every class_print procedure would need an extra input.
(Incidentally, for printing one normally needs at least two control
variables, one for depth of nesting and one for length of tails,
and Poplog Pop-11 is wrong to have only one variable for nesting,
namely pop_pr_level)
I suspect that Ray's type of solution would be acceptable for
printing, simply because once you get into any printing procedure
you stay within printing procedures which call other printing
procedures explicitly or implicitly (e.g. via class_print), so
there's no real difficulty in passing on the extra parameters.
More generally, however, there are cases where there's a context,
e.g. a database of some kind that's extended by a hypothetical
action, and various different procedures can get called which only
*indirectly*, via several levels of procedure calling eventually
invoke the procedure that further extends the context. For that
situation the extra parameter would have to be supplied to lots of
procedures that do nothing with it except pass it on. If you have
lots of such parameters (cucharout, prmishap, database, interrupt,
etc. etc.) it gets messy. Then Robin's solution of providing a
single environment that's passed on by every procedure looks like
the only attractive solution.
What that amounts to is abandoning global variables that can be
changed locally. It's a consistent way to do things, and maybe has
some nice properties. I suspect that for a large team of programmers
developing a suite of interrelated programs that can call one
another recursively it may be less convenient and less efficient
than using global variables that are dynamically scoped using
dlocal. But I don't know.
[RD]
> Now who has a compiler I can syntax check this with!!
A nice project for a student learning to use Pop-11's compiler
development tools?
Aaron
--
--
Aaron Sloman,
School of Computer Science, The University of Birmingham, B15 2TT, England
EMAIL A.Sloman@cs.bham.ac.uk OR A.Sloman@bham.ac.uk
Phone: +44-(0)21-414-3711 Fax: +44-(0)21-414-4281
|