hY,
I have a feeling this is a bug.
(defvar mylist '(:one :two :three))
(iter (for var on mylist) (collect (car var) into result) (finally (return (values result var)))) (:ONE :TWO :THREE) (:THREE)
I think var should be empty at the end, so the result would match the result of loop as
(loop for var on mylist collect (car var) into result finally (return (values result var))) (:ONE :TWO :THREE) NIL
The problem is caused by the end test code location. The bold lines should appear in reverse order, I think.
(macroexpand-1 '(iter (for var on mylist) (collect (car var) into result) (finally (return (values result var))))) (LET* ((#:LIST214 NIL) (VAR NIL) (RESULT NIL) (#:END-POINTER215 NIL) (#:TEMP216 NIL)) (BLOCK NIL (TAGBODY (PROGN (SETQ #:LIST214 MYLIST)) LOOP-TOP-NIL (PROGN
* (IF (ATOM #:LIST214) (GO LOOP-END-NIL)) (SETQ VAR #:LIST214)* (SETQ #:LIST214 (CDR #:LIST214)) (PROGN (SETQ #:TEMP216 (LIST (CAR VAR))) (SETQ #:END-POINTER215 (IF RESULT (SETF (CDR #:END-POINTER215) #:TEMP216) (SETQ RESULT #:TEMP216))) RESULT)) (PROGN) (GO LOOP-TOP-NIL) LOOP-END-NIL (PROGN (RETURN (VALUES RESULT VAR)))) NIL)) Best, ` bg`
Gábor Balázs wrote:
The bold lines should appear in reverse order, I think. (IF (ATOM #:LIST214) (GO LOOP-END-NIL)) (SETQ VAR #:LIST214)
You can't invert the order, because that would be a type violation. Iterate may make use of types, see *declare-variables*.
Furthermore, the spec does not guarantee that value after the end of the iteration. Quite to the contrary, it's explicitly disallowed. Quote:
"In all cases, the value of the driver variable on exit from the loop, including within the epilogue code (see the finally clause), is undefined."
Regards, Jörg Höhle
On Wed, May 21, 2014 at 3:45 AM, Joerg-Cyril.Hoehle@t-systems.com wrote:
Gábor Balázs wrote:
The bold lines should appear in reverse order, I think. (IF (ATOM #:LIST214) (GO LOOP-END-NIL)) (SETQ VAR #:LIST214)
You can't invert the order, because that would be a type violation. Iterate may make use of types, see *declare-variables*.
Furthermore, the spec does not guarantee that value after the end of the iteration. Quite to the contrary, it's explicitly disallowed. Quote:
"In all cases, the value of the driver variable on exit from the loop, including within the epilogue code (see the finally clause), is undefined."
This is indeed a surprise for me. Definitely should be on the "Differences between LOOP and iterate" page.
But I think iterate should make the drivers accessible in the epilogue. This code is not that nice and confusing.
(iter (for var on mylist) (for var2 = (rest var)) (collect (car var) into result) (finally (return (values result var2)))) (:ONE :TWO :THREE) NIL
So is there some design reason against making the drivers accessible in the finally clause? Maybe, could just iterate parse the finally clause and make the proper adjustments if necessary?
`bg`
Regards, Jörg Höhle
Gábor Balázs wrote:
So is there some design reason against making the drivers accessible in the finally clause?
I think it's simply more robust to locally roll your own iterate extension that exhibits the behavior you need using the defined extension API, rather than produce an incompatible Iterate with an obscure change in semantics. Mind dll hell!
Do you want to debug a large app that exhibits an obscure bug that would eventually be traced down to the user using a version of the Iterate library that differs from yours in that aspect?
Definitely should be on the "Differences between LOOP and iterate" page.
Good point. Who submits a patch to the LaTeX documentation?
Regards, Jörg Höhle
It's worth remembering that this is undefined behavior. It is usually safe to start defining behavior in undefined cases as they should be, by definition, backwards compatible.
To be honest, this is not an aspect of Iterate that I was aware of. It is a bit surprising that this is undefined behavior. Gabor's examples are a bit theoretical, but if my understanding is correct, the following functions have undefined behavior.
(defun split-on1 (obj list &key (test 'eql)) (iter (for (x . list-b) :on list) (collect x :into list-a) (until (funcall test obj x)) (finally (return (list list-a list-b)))))
...or, if you prefer that the element goes on the second list,...
(defun split-on2 (obj list &key (test 'eql)) (iter (for (x . list-b) :on list) (until (funcall test obj x)) (collect x :into list-a) (finally (return (list list-a (cons x list-b))))))
I suppose that the specification states that both of these are undefined (due to the usage of x in on-split1 and x and rest in on-split2), though some testing seems to suggest that they work. Seems like defining the bindings would be a step in the right direction. Am I missing something?
On Wed, May 21, 2014 at 11:17 AM, Joerg-Cyril.Hoehle@t-systems.com wrote:
Gábor Balázs wrote:
So is there some design reason against making the drivers accessible in
the finally clause? I think it's simply more robust to locally roll your own iterate extension that exhibits the behavior you need using the defined extension API, rather than produce an incompatible Iterate with an obscure change in semantics. Mind dll hell!
Do you want to debug a large app that exhibits an obscure bug that would eventually be traced down to the user using a version of the Iterate library that differs from yours in that aspect?
Definitely should be on the "Differences between LOOP and iterate" page.
Good point. Who submits a patch to the LaTeX documentation?
Regards, Jörg Höhle _______________________________________________ Iterate-devel mailing list Iterate-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/iterate-devel