On 10/15/12 10:51 AM, Felix wrote:
[...] It can be considered a bug, indeed. The problem is that we have to pass
an additional argument to parameter-functions to mark the situation
when a parameter gets "restored". "parameterize" expands into something
like
(let ((param1 ...) ...)
(let ((old-value1 #f) ...)
(dynamic-wind
(lambda ()
<set old-valueN to value of paramN>)
(lambda ()
<body>)
(lambda ()
<restore value of paramN>))))
The restoration can not simply by "(paramN <oldval>)", since we must
avoid calling the guard procedure (if it exists). Being too lazy / too
afraid to change the implementation of parameter procedures (which is
relatively complicated, including threading issues, as parameters are
thread-local), and because I saw the opportunity to cut a tiny bit of
runtime by simply omitting the check for surplus arguments (as is done
in various old-school Lisp dialects, in C (or undeclared procedures,
or procedures with "..."), in Lua, and in a number of other scripting
languages), I decided to drop the check completely. The parameterize-
issue is now handled by simply passing an extra flag argument that
indicates "restoration". Parameter-like procedures that take a single
optional argument will be handled transparently - they simply ignore
the second flag argument, which is fine, as they don't have a guard
procedure.
I hope this explanation is not too confusing. If it is, I'll try to
give more examples.
Note that R5RS only requires "rest"-arguments, which, by definition,
can be of arbitrary length. Chicken's "#!optional" just builds on top
of R5RS' rest-parameters, BTW.
I had a lot to say about rest args and optional args being two different
things from a user's perspective, and each one has different uses and
expected behavior. But, I think I have already talked too much about why
the old behavior should be restored. So instead, I will just suggest a
possible technical solution. :-)
Here is how I understand the situation: in order to avoid unnecessary
computation, we want to avoid invoking the guard procedure when the old
parameter value is restored at the end of parameterize. So, we need
parameter-functions to accept a second arg, which is a flag to tell it
to bypass the guard procedure.
So I wonder: is there any problem with simply adding support for a
second arg to the parameter-functions, without removing the arg check
for all procedures that use #!optional? Even in Chicken 4.7,
parameter-functions silently accept extra arguments, so there would be
no user-visible change in the way parameter-functions are called.
The only bad effect I could see, would be that Chicken users might think
the ability to bypass the guard procedure is a real feature of Chicken,
instead of a hack to make parameterize more efficient. But, that problem
could be avoided by checking that "bypass guard" argument is a certain
unexported symbol (maybe even a gensym) that Chicken users would not
(normally) have access to. To put it into pseudocode, a
parameter-function might behave something like this:
| (lambda args
(case (length args)
((0) (get-this-parameter-value))
((1) (set-this-parameter-value (guard-procedure (car args))))
(else (if (eq? ##bypass-parameter-guard## (cadr args))
(set-this-parameter-value (car args))
(set-this-parameter-value (guard-procedure (car
args)))))))||
|
This is still a hack, but at least it is just a small hack which affects
only parameterize, and only in the intended way (bypassing the guard
procedure when restoring their value). Then, the old behavior of
#!optional can be safely restored.
Maybe I have misunderstood something, and this solution would not work
for some reason. If so, please help me understand.
- John
_______________________________________________
Chicken-users mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/chicken-users