* Ivar Rummelhoff <iva...@math.uio.no> | The Emacs lisp CL-package (by Dave Gillespie) has a convenient macro | named `letf'. Do anyone know if there is a Common Lisp implementation | available somewhere?
Some time ago, I wrote these, and put them in my customized lisp, but I have not used them much since then.
* Joe Marshall <jmarsh...@alum.mit.edu> | I suggest that you move the setter forms to within the unwind-protect:
Doing so gives you nothing but a false sense of improved security.
| The problem with LETF (as written) is that it will not work in a | multitasking environment, so be careful with it.
It will work exactly as well as, and no better than, doing the same settings "manually", i.e., without the macro. This is intentional. The problem is not with letf, but with setting such places. This is actually very important to understand: letf does not make it worse, but it also cannot protect you from the problem.
#:Erik -- If this is not what you expected, please alter your expectations.
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | I suggest that you move the setter forms to within the unwind-protect:
> Doing so gives you nothing but a false sense of improved security.
True, there are still potential holes, but moving the setters to within the unwind-protect will at least make an *attempt* to recover that should succeed in a variety of situations where having it outside will fail.
Suppose we have a LETF like this: (letf (((xyzzy y) 22) ((car (fun x)) (foobar a b c))) (do-something))
Here are the failure modes: 1. A `value' cannot be computed. For instance, (foobar a b c) throws an error. Since all values are computed before any binding, these forms do not need to be protected.
2. A `place' cannot be computed. For instance, (fun x) throws an error. Since all places are computed before any binding, these forms do not need to be protected.
3. The `access' cannot be computed. For instance, (xyzzy y) throws an error, or (fun x) does not return a cons. Since all values are computed before any binding, these forms do not need to be protected.
4. The `store' cannot be computed. For instance, the implied rplaca or (setf xyzzy) throws an error. Should one of these forms throw an error, that particular binding will not have happened, but prior bindings will.
5. The `store' is not idempotent. For instance, (setf xyzzy) acts differently each time it is called. In this case you are probably hosed.
Now the original macro computes the values, the places, the accesses and the first set of stores outside the unwind protect. Should some of the stores run, but one throws out, the stores that have already been done will not be undone since we are outside the unwind-protect.
However, by placing the stores inside the unwind-protect, should one of the stores error out, we will run the cleanup forms. Of course the cleanup forms run the same stores, so it is virtually certain that the cleanup forms will error out as well, *but probably at the same form*.
This is the key. Most of the SETF store functions will be no more complicated than RPLACA (in a typical case). So it is highly likely that the ones able to run to completion upon entry they will be able to run to completion on exit.
We are also relying on the store functions being run in the same order when binding and unbinding. If the order were reversed, for example, the above argument doesn't hold.
Also consider manually aborting out of the first set of store functions (I think a more likely scenario than erroring out). Even if only some of the modifications run, and all of the `unmodifications' run, it is presumably ok to store the original value `on top of itself'.
So although moving the store functions to inside the unwind-protect is no panacea, it will likely make your life easier.
> | The problem with LETF (as written) is that it will not work in a > | multitasking environment, so be careful with it.
> It will work exactly as well as, and no better than, doing the same > settings "manually", i.e., without the macro. This is intentional. > The problem is not with letf, but with setting such places. This is > actually very important to understand: letf does not make it worse, > but it also cannot protect you from the problem.
Yes. The problem is that LETF *looks* like it is binding a location similarly to how LET binds special variables. (Indeed, that is the point, is it not?) In this case looks are deceiving, and it may perhaps be better to avoid using LETF in favor of an unwind-protect and a pair of SETF's because the latter are less likely to mislead a casual viewer.
> #:Erik > -- > If this is not what you expected, please alter your expectations.
they don't seem to deal with declarations properly. This can be particularly important in LET and LET* forms. Is it a finite amount of work to get the basic declarations to work with LETF(*) as defined in the previous post?
* David Bakhash <ca...@alum.mit.edu> | One thing I want to know about these macros... | they don't seem to deal with declarations properly. This can be | particularly important in LET and LET* forms. Is it a finite amount of | work to get the basic declarations to work with LETF(*) as defined in | the previous post?
The places they are supposed to be used on are not variables that will be used in the body, so declarations are less relevant than in most other places. It is of course a finite amount of work to make declarations work: Wrap a let form around the body instead progn, as always when you want declarations to work.
#:Erik -- If this is not what you expected, please alter your expectations.
Erik Naggum <e...@naggum.no> writes: > declarations work: Wrap a let form around the body instead progn, as > always when you want declarations to work.
yeah. thanks. that's a very simple way to handle it that I missed.
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | I would imagine it is because Allegro CL doesn't handle LOCALLY > | declarations correctly.
> Say what? I haven't even used locally sufficiently to realize there > could be problems with it if I did. How should something you claim > that I cannot even verify affect my decisions not to _start_ using > something?
Verifying whether LOCALLY works or not is easy, see below.
It is certainly plausible that at some time in the past you experimented with using LOCALLY, found it didn't do what you wanted, and therefore made the decision not to _start_ using it.
Be that as it may, I was indulging in idle speculation. But my statement was not devoid of value: there is a bug in how Allegro CL handles LOCALLY.
> Sorry, but your thinking is just too weird for me.
No need to apologize.
> Incidentally, where I have used locally, which is not in macros, it > has worked as I have wanted it to. Fault my understanding of how it > _should_ work if you have to publish more of your imagination, but > perhaps you could elaborate on the substance of your claim instead > of making up silly and imaginary consequences of it?
I draw your attention to the disassembly of following the two segments of code. The LOCALLY used in the first example provides sufficient type information for the compiler to be able to optimize the call to AREF. As you can see from the output of the compiler and the disassembled code, the type declarations in test-one are not used during the compilation of AREF.
Granted, the compiler is always free to ignore declarations (except for special ones, of course), but given that the compiler does produce optimized code when the declarations follow a LET statement, and fails to do so when the declarations follow a LOCALLY, it is fair to say that LOCALLY isn't working.
(defun test-one (y x) (check-type x array-index) (check-type y (simple-array t (*))) (locally (declare (type array-index x) (type (simple-array t (*)) y) (optimize (speed 3) (safety 1)) #+allegro (:explain :calls :types)) (aref y x)))
;Examining a call to AREF with arguments: ; symeval Y type T ; symeval X type T ; which returns a value of type T ;Generating a non-inline NON-SELF tail jump to AREF
(defun test-two (y x) (check-type x array-index) (check-type y (simple-array t (*))) (let ((x x) (y y)) (declare (type array-index x) (type (simple-array t (*)) y) (optimize (speed 3) (safety 1)) #+allegro (:explain :calls :types)) (aref y x)))
;Examining a call to AREF with arguments: ; symeval Y type (SIMPLE-ARRAY T (*)) ; symeval X type (INTEGER 0 16777216) ; which returns a value of type T
* Joe Marshall wrote: > Granted, the compiler is always free to ignore declarations (except > for special ones, of course), but given that the compiler does produce > optimized code when the declarations follow a LET statement, and fails > to do so when the declarations follow a LOCALLY, it is fair to say > that LOCALLY isn't working.
I don't think that's fair at all. If something is optional and a vendor doesn't do it then they just don't do it. And ACL does listen to SPECIAL declarations in LOCALLY.
Tim Bradshaw <t...@cley.com> writes: > * Joe Marshall wrote:
> > Granted, the compiler is always free to ignore declarations (except > > for special ones, of course), but given that the compiler does produce > > optimized code when the declarations follow a LET statement, and fails > > to do so when the declarations follow a LOCALLY, it is fair to say > > that LOCALLY isn't working.
> I don't think that's fair at all. If something is optional and a > vendor doesn't do it then they just don't do it. And ACL does listen > to SPECIAL declarations in LOCALLY.
Well, if declarations in LOCALLY are being pretty much ignored, you could hardly say it *is* working.
How about `LOCALLY isn't working as one might expect it to'?
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | How about `LOCALLY isn't working as one might expect it to'?
> I think this is a very good way to phrase your complaints, as it > stresses your expectations, not how it _is_ working. I'm as > interested as anyone in as powerful and useful behavior as possible > in any Common Lisp system, but I'm also a language lawyer after many > years of exposure to the standards processes of several languages, > and there's not much to say on this except: only if you can > demonstrate that your expectations are such that a failure to > indulge same constitutes a violation of that one principally > important property of an implementation of standard, namely > conformance, you can no longer whack people over the head for > breaking the promise to be conformant, you are discussing the > quality of implementation, as determinable in a open marketplace > where the standard and the conformance to it constitute a baseline.
I never said Franz wasn't conformant, I merely pointed out that they don't *do* much with the declarations that follow a LOCALLY, and in particular, they don't perform the optimizations they would perform if the declarations were at the beginning of a lambda-body or a let.
> In short: Your expectations are demonstrably irrelevant.
The actual effect (or lack thereof) of a LOCALLY statement in Franz Lisp is relevant.
> #:Erik > -- > If this is not what you expected, please alter your expectations.
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | How about `LOCALLY isn't working as one might expect it to'?
> I think this is a very good way to phrase your complaints, as it > stresses your expectations, not how it _is_ working. I'm as > interested as anyone in as powerful and useful behavior as possible > in any Common Lisp system, but I'm also a language lawyer after many > years of exposure to the standards processes of several languages, > and there's not much to say on this except: only if you can > demonstrate that your expectations are such that a failure to > indulge same constitutes a violation of that one principally > important property of an implementation of standard, namely > conformance, you can no longer whack people over the head for > breaking the promise to be conformant, you are discussing the > quality of implementation, as determinable in a open marketplace > where the standard and the conformance to it constitute a baseline.
I never said Franz wasn't conformant, I merely pointed out that they don't *do* much with the declarations that follow a LOCALLY, and in particular, they don't perform the optimizations they would perform if the declarations were at the beginning of a lambda-body or a let.
> In short: Your expectations are demonstrably irrelevant.
The actual effect (or lack thereof) of a LOCALLY statement in Franz Lisp is relevant.
> #:Erik > -- > If this is not what you expected, please alter your expectations.
> I never said Franz wasn't conformant, I merely pointed out that they > don't *do* much with the declarations that follow a LOCALLY, and in > particular, they don't perform the optimizations they would perform if > the declarations were at the beginning of a lambda-body or a let.
> > In short: Your expectations are demonstrably irrelevant.
> The actual effect (or lack thereof) of a LOCALLY statement in Franz > Lisp is relevant.
Joe, your analysis is slightly off. In the ACL compiler the effect of declarations at the head of a LOCALLY form is exactly the same as at the head of a LET or LAMBDA body.
What the compiler fails to do is to process _free_ type declarations. Recall that a "free" declaration is one concerning about a binding made at some contour interior to the one that established that binding. So:
These forms are treated identically, and neither will be optimized the way the programmer clearly intends. It is only free type declarations that are ignored (other than syntax checking, etc.) and OPTIMIZE, SPECIAL, and other free declaratione are processed as one would expect.
The only difference between a LOCALLY and a LET with no bindings is that the former when used at top-level passes the quality of top-level-ness to its body. This is as required by the ANS.
I think you, Erik, and I would all agree that it would be better if the compiler observed free type declarations, just as we all agree it is not required that it do so. I expect I am somewhat more critical of the failure than Erik, however, because the failure mode is very obscure (e.g. your analysis was incorrect) and the result is that the compiler does not do what the programmer expects it to do. Furthermore, the circumstances where the compiler doesn't do the right thing are very similar to the circumstances in which it does do the right thing, and the failing construct is one that is or ought to be in the vocabulary of programmers. This glitch in the compiler is therefore pernicious to portability of code and portability of programmers.
> Joe, your analysis is slightly off. In the ACL compiler the effect of > declarations at the head of a LOCALLY form is exactly the same as at the > head of a LET or LAMBDA body.
> What the compiler fails to do is to process _free_ type declarations.
Ah, now I understand what's going on there. Thank you for clarifying it.
> I think you, Erik, and I would all agree that it would be better if the > compiler observed free type declarations, just as we all agree it is not > required that it do so.
But if we all agreed with Erik, he'd have no fodder for his acerbic philippics!
> I expect I am somewhat more critical of the failure than Erik, > however, because the failure mode is very obscure (e.g. your > analysis was incorrect) and the result is that the compiler does not > do what the programmer expects it to do.
Other problems are that although the failure mode is obscure, the idiom that generates it is common, and there isn't an easy workaround (other than decorating your code with lots of `THE' expressions).
Given that Allegro does a good job with type inference in other situations, I would guess that Franz intended or intends to process free type declarations, and would thus see this as a bug, even though it techically does not produce incorrect code.
... > It is only free type declarations > that are ignored (other than syntax checking, etc.) and OPTIMIZE, > SPECIAL, and other free declaratione are processed as one would > expect.
Could you point out where in the standard it indicates that an implementation may ignore a free type declaration if it obeys a bound one?
Thanks,
/Jon
-- Jon Anthony Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383 "Nightmares - Ha! The way my life's been going lately, Who'd notice?" -- Londo Mollari
Erik Naggum <e...@naggum.no> writes: > * Joe Marshall <jmarsh...@alum.mit.edu> > | But if we all agreed with Erik, he'd have no fodder for his acerbic > | philippics!
* Jon S Anthony <j...@synquiry.com> | Could you point out where in the standard it indicates that an | implementation may ignore a free type declaration if it obeys a | bound one?
This is a completely bogus question. Pull yourself together and _think_ carefully about what you request from the standard, and to what level of redundant detail it had to go if it were able to answer your question.
#:Erik, sighing -- If this is not what you expected, please alter your expectations.
> * Jon S Anthony <j...@synquiry.com> > | Could you point out where in the standard it indicates that an > | implementation may ignore a free type declaration if it obeys a > | bound one?
> This is a completely bogus question. Pull yourself together and > _think_ carefully about what you request from the standard,
Yes, it is if you misunderstand the intent. I realize what your point is here - the standard doesn't have to explicitly state this (then again maybe you mean more than this and I really am totally lost.)
> and to what level of redundant detail it had to go if it were able > to answer your question.
That's exactly right - I don't expect such redundant detail, and that's why I didn't ask for "where it _says_" this. What I was "admitting to" was that I didn't see where/how this comes about. Certainly 3.3.1 says an implementation is free to ignore any type declaration specifier anywhere, and thus such free ones can be ignored. But I had the (mis?)impression that something more was being indicated by S Haflich.
/Jon
-- Jon Anthony Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383 "Nightmares - Ha! The way my life's been going lately, Who'd notice?" -- Londo Mollari
> Could you point out where in the standard it indicates that an > implementation may ignore a free type declaration if it obeys a > bound one?
An implementation is free to ignore *all* type declarations, or not, as it chooses. An implementation is perfectly entitled to listen to type declarations only on Thursday afternoons when the moon is full.
> Steven M. Haflich wrote: > > It is only free type declarations > > that are ignored (other than syntax checking, etc.) and OPTIMIZE, > > SPECIAL, and other free declaratione are processed as one would > > expect.
> Could you point out where in the standard it indicates that an > implementation may ignore a free type declaration if it obeys a > bound one?
Others have already replied as to the text of the ANS, but in addition, think about the issue from the underside:
A correct type declaration never has any semantic effect on a correct program. (Obvious exception: A slot type declaration affects what is returned by slot-definition-type, but that is visible only using the MOP.) If you can tell whether the implementation did or did not observe a type declaration, using only behavior mandated in the ANS, then your program and/or its declarations were incorrect and violated the standard.
An implementation may ignore any type declaration whenever it likes because no type declaration can have any observable semantic effect on correct code. A correct type declaration may have effect on speed or space or whatever, but not semantics.
s...@alum.mit.edu wrote: > A correct type declaration never has any
semantic effect on a correct
> program. (Obvious exception: A slot type
declaration affects what is
> returned by slot-definition-type, but that is
visible only using the
> MOP.) If you can tell whether the
implementation did or did not
> observe a type declaration, using only behavior
mandated in the ANS,
> then your program and/or its declarations were
incorrect and violated
> the standard.
Yes, this is all very straight forward and standard stuff.
> An implementation may ignore any type
declaration whenever it likes
> because no type declaration can have any
observable semantic effect
> on correct code. A correct type declaration may have effect on > speed or space or whatever, but not semantics.
Yes, again this is clear (and a reasonable _rationale_ for why the rule in 3.3.1 exists).
I think the whole thing boils down to my thinking that the (rather extensive) exchanges by folks I consider knowledgeable indicated that there was something more to all of this than that ACL simply took advantage of the rule in one context and not another. That appears to have been the major error on my part.
/Jon
-- Jon Anthony Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383 "Nightmares - Ha! The way my life's been going lately, Who'd notice?" -- Londo Mollari
jsa...@my-deja.com writes: > I think the whole thing boils down to my thinking > that the (rather > extensive) exchanges by folks I consider > knowledgeable indicated that > there was something more to all of this than that > ACL simply took > advantage of the rule in one context and not > another. That appears to > have been the major error on my part.
Well, IMHO the choice isn't quite as arbitrary as that: Since the HyperSpec already differentiates between free and bound declarations (not only type declarations) for the purposes of scope, this is a less arbitrary boundary to draw than others. Also note that there is another important distinction between bound and free declarations: You can only have one bound declaration of any sort for any binding, whereas you can have many free declarations for a binding. Or to put it another way: Free declarations introduce their own scoping system, whereas bound declarations live off the scoping system already in place for bindings. Thus it is a "natural" limit for the support of declarations. ACL isn't the only implementation that sets a limit there: CMUCL for example doesn't heed free ignore and ignorable declarations, as do many other implementations.
Regs, Pierre.
-- Pierre Mai <p...@acm.org> PGP and GPG keys at your nearest Keyserver "One smaller motivation which, in part, stems from altruism is Microsoft- bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
> > there was something more to all of this than that ACL simply took > > advantage of the rule in one context and not another. That appears > > to have been the major error on my part.
> Well, IMHO the choice isn't quite as arbitrary as that:
No where, in anything I said, do I indicate that this choice was arbitrary. There may well be very good reasons for ACL doing this (as you indicate) and that is why it would be "taking advantage of" and not simply using (arbitrarily) the rule.
/Jon
-- Jon Anthony Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383 "Nightmares - Ha! The way my life's been going lately, Who'd notice?" -- Londo Mollari