On 2009-01-07, Pascal Costanza <p...@p-cos.net> wrote:
> Hm, the following seems to go into an endless loop in two Lisp > implementations I checked:
> (loop finally (print 'screw-you))
> Is this according to the spec?
It's not a simple loop form because simple loop must have a body that has only compound forms. If there is any atom among the forms, even if the first form is a compound, it's an extended loop. So this is an extended loop with a FINALLY clause that is never reached, since there is no termination test, nor any explicit LOOP-FINISH or RETURN.
6.1.1.6 Order of Execution says: ``Execution is repeated until a clause terminates the loop or until a return, go or throw form is encountered which transfers control to a point outside the loop.''
I.e. the lack of any termination tests isn't treated as a positive termination test, similarly to the way (OR) yields NIL. It's as if the set of termination tests constitutes a logical disjunction which is false if empty.
Kaz Kylheku <kkylh...@gmail.com> wrote: +--------------- | Pascal Costanza <p...@p-cos.net> wrote: | > Hm, the following seems to go into an endless loop in two Lisp | > implementations I checked: | > (loop finally (print 'screw-you)) | > Is this according to the spec? ... | It's not a simple loop form ... So this is an extended loop with a FINALLY | clause that is never reached, since there is no termination test, nor any | explicit LOOP-FINISH or RETURN. | | 6.1.1.6 Order of Execution says: ``Execution is repeated until a clause | terminates the loop or until a return, go or throw form is encountered | which transfers control to a point outside the loop.'' +---------------
On 2009-01-08, William James <w_a_x_...@yahoo.com> wrote:
> Pascal Costanza wrote:
>> Hm, the following seems to go into an endless loop in two Lisp >> implementations I checked:
>> (loop finally (print 'screw-you))
>> Is this according to the spec?
>> Pascal
> Ruby:
> until p :screw_you ;end
Are you competing with yourself to see what is the shortest snippet of Lisp that you can misunderstand?
Or don't you see how the above Ruby evaluates "p :screw you", whereas (print 'screw-you) is unreachable in the Lisp code?
Using the nil return value of p is poor programming style because the action of printing is not related to logical falsehood. The return value of an i/o function should only be used if it indicates the outcome of that operation. If p always returned 5, would you use in place of the constant 5?
Kaz Kylheku wrote: > On 2009-01-07, Pascal Costanza <p...@p-cos.net> wrote: >> Hm, the following seems to go into an endless loop in two Lisp >> implementations I checked:
>> (loop finally (print 'screw-you))
>> Is this according to the spec?
> It's not a simple loop form because simple loop must have a body that has only > compound forms. If there is any atom among the forms, even if the first form is > a compound, it's an extended loop. So this is an extended loop with a FINALLY > clause that is never reached, since there is no termination test, nor any > explicit LOOP-FINISH or RETURN.
> 6.1.1.6 Order of Execution says: ``Execution is repeated until a clause > terminates the loop or until a return, go or throw form is encountered > which transfers control to a point outside the loop.''
> I.e. the lack of any termination tests isn't treated as a positive termination > test, similarly to the way (OR) yields NIL. It's as if the set of termination > tests constitutes a logical disjunction which is false if empty.
Finally is normally used to return something (other than nil) or to do something once the iteration activity has ended, which does not happen in your case. Your code in practice is tantamount to (loop) though in theory it would print something at the end of eternity (much like two paralel lines are said to join at infinity).
kodi...@eurogaran.com wrote: >> (loop finally (print 'screw-you)) > Finally is normally used to return something (other than nil) > or to do something once the iteration activity has ended, which > does not happen in your case. > Your code in practice is tantamount to (loop) > though in theory it would print something at the end of eternity > (much like two paralel lines are said to join at infinity).
Yep, got that. ;)
I was under the impression that (loop finally ...) should just immediately terminate because there is no loop clause there. Wrong idea... ;)
On Jan 8, 11:53 am, Pascal Costanza <p...@p-cos.net> wrote:
> I was under the impression that (loop finally ...) should just > immediately terminate because there is no loop clause there. Wrong > idea... ;)
Not so wrong. A clever enough compiler would see the loop is empty and produce code that proceeds inmediatly to the print statement. (In case the programmer really wanted an infinite loop instead of the equivalent final result, she/he could choose to leave the code interpreted.) This means the compiler could produce an infinitely quick code, which is conceptually interesting. ...and by the way completely opposite to what the SBCL compiler does, which is to delete the finally clauses as being considered unreacheable code.
On 2009-01-08, kodi...@eurogaran.com <kodi...@eurogaran.com> wrote:
>> (loop finally (print 'screw-you)) > Finally is normally used to return something (other than nil) > or to do something once the iteration activity has ended, which > does not happen in your case. > Your code in practice is tantamount to (loop) > though in theory it would print something at the end of eternity > (much like two paralel lines are said to join at infinity).
Whether or not parallel lines join depends on the choice of fifth postulate.
Maybe an analogous postulate is buried in imperative programming. :)
> > Your code in practice is tantamount to (loop) > > though in theory it would print something at the end of eternity > > (much like two paralel lines are said to join at infinity).
> Whether or not parallel lines join depends on the choice of fifth postulate. > Maybe an analogous postulate is buried in imperative programming. :)
There is indeed a non-resolved issue we touched here, namely the programmer's purpose: Is it only to achieve the result? or to achive it EXACTLY the way s/he has programmed? In other words: Should the compiler be allowed for instance to eliminate the redundant code in (setq a 3) (setq a 3) (setq a 3) (setq a 3) ? This is a rather phylosophical -though very fundamental- question, hardly ever touched on programming books. My opinion is that it should be allowed to do so, since one has in lisp the alternative of interpreted code -at least in principle- and compiler graduation (optimization levels, etc.)
fugue88 <fugu...@gmail.com> writes: >> In other words: Should the compiler be allowed for instance to >> eliminate the redundant code in >> (setq a 3) (setq a 3) (setq a 3) (setq a 3) ?
> In general, no. You may be writing to a memory-mapped device, or > otherwise have unusual memory semantics.
> Although, maybe in Lisp such a thing is okay. You couldn't SETQ to > memory involved with an FFI, could you?
>> In other words: Should the compiler be allowed for instance to >> eliminate the redundant code in >> (setq a 3) (setq a 3) (setq a 3) (setq a 3) ?
> In general, no. You may be writing to a memory-mapped device, or > otherwise have unusual memory semantics.
> Although, maybe in Lisp such a thing is okay. You couldn't SETQ to > memory involved with an FFI, could you?
A symbol expression can stand for another expression---symbol or compound---thanks to symbol macros; because of this possiblity, SETQ is required to handle assignment to forms other than symbols, just like SETF.
You can SETF to anything for which you can write a setf expander, and you can SETQ any compound form that designates a setf-able place, if you alias that place behind a symbol macro.
In article <20090120132255....@gmail.com>, Kaz Kylheku <kkylh...@gmail.com> wrote:
> On 2009-01-14, fugue88 <fugu...@gmail.com> wrote: > >> In other words: Should the compiler be allowed for instance to > >> eliminate the redundant code in > >> (setq a 3) (setq a 3) (setq a 3) (setq a 3) ?
> > In general, no. You may be writing to a memory-mapped device, or > > otherwise have unusual memory semantics.
> > Although, maybe in Lisp such a thing is okay. You couldn't SETQ to > > memory involved with an FFI, could you?
> A symbol expression can stand for another expression---symbol or > compound---thanks to symbol macros; because of this possiblity, SETQ is > required to handle assignment to forms other than symbols, just like SETF.
Presumably all such optimizations are done AFTER macro expansion, so this doesn't really seem relevant.
-- Barry Margolin, bar...@alum.mit.edu Arlington, MA *** PLEASE post questions in newsgroups, not directly to me *** *** PLEASE don't copy me on replies, I'll read them in the group ***
Barry Margolin <bar...@alum.mit.edu> writes: > In article <20090120132255....@gmail.com>, > Kaz Kylheku <kkylh...@gmail.com> wrote:
>> On 2009-01-14, fugue88 <fugu...@gmail.com> wrote: >> >> In other words: Should the compiler be allowed for instance to >> >> eliminate the redundant code in >> >> (setq a 3) (setq a 3) (setq a 3) (setq a 3) ?
>> > In general, no. You may be writing to a memory-mapped device, or >> > otherwise have unusual memory semantics.
>> > Although, maybe in Lisp such a thing is okay. You couldn't SETQ to >> > memory involved with an FFI, could you?
>> A symbol expression can stand for another expression---symbol or >> compound---thanks to symbol macros; because of this possiblity, SETQ is >> required to handle assignment to forms other than symbols, just like SETF.
> Presumably all such optimizations are done AFTER macro expansion, so > this doesn't really seem relevant.
Yes, sorry, with time we forgot the level we were considering.
We have to consider two situations:
- with a single thread, the memory stores can be collapsed, it will make no difference.
- with several threads, or if the memory designated by A is not the standard Common Lisp memory, but some strange device (eg. failing RAM, or actual device register), then the semantics of the four consecutive stores will probably be different from a single store. But this situations is outside the scope of the Common Lisp standard, and it's up to the implementation to know what it does. I assume that there would be implementation specific declarations to handle these cases:
(let (a b c) (declare (system:device-register (#xff0110000a A)) (system:volatile b)) (create-thread (lambda () (loop (setf b (do-something-with b))))) (setq a 3) (setq a 3) (setq a 3) (setq a 3) ; not collapsed (setq b 3) (setq b 3) (setq b 3) (setq b 3) ; not collapsed (setq c 1) (setq c 2) (setq c 3) (setq c 4)) ; collapsed ;; in the later specific case, C could even be ellided.