|
From: | John Croisant |
Subject: | Re: [Chicken-users] Bug with #!optional in Chicken 4.8.0 |
Date: | Tue, 16 Oct 2012 18:24:14 -0400 |
User-agent: | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) Gecko/20121010 Thunderbird/16.0.1 |
On 10/15/12 10:51 AM, Felix wrote:
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. :-)[...] 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.
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
[Prev in Thread] | Current Thread | [Next in Thread] |