Prev: Macro with-timeout
Next: Confirmed: never, Ever, EVER use nreverse unless you (I meanI) damn well know what is going on
From: Mirko on 7 Dec 2009 17:01 I had no idea nreverse could reach this deep (amounting to shallow understanding/thinking?). This is the code snippet: (let ((data (tecplot-data data-pod var :type :boundary :avg avg))) (coerce (reverse data) 'vector))) Now (tecplot-data ... ) amounts to (aref (data object) 6) where (data object) returns a vector of 9 lists. `data' never existed in the let construct, and the direct reference to the original list was maintained across two function calls. Makes perfect sense in retrospect, but for a while I thought I was seeing gremlins. Argh ... Back to our regular programming.
From: Mirko on 7 Dec 2009 21:16 On Dec 7, 6:06 pm, Kaz Kylheku <kkylh...(a)gmail.com> wrote: > On 2009-12-07, Mirko <mirko.vuko...(a)gmail.com> wrote: > > > I had no idea nreverse could reach this deep (amounting to shallow > > understanding/thinking?). > > > This is the code snippet: > > > (let ((data (tecplot-data data-pod var :type :boundary :avg avg))) > > (coerce (reverse data) 'vector))) > > If you don't know that tecplot-data returns a newly allocated > list, JFY (just for you), then you have no right to use nreverse. even more embarassingly, I am the author of tecplot-data. Thanks for exposition. Mirko
From: Mirko on 8 Dec 2009 10:14 On Dec 8, 6:16 am, Pascal Costanza <p...(a)p-cos.net> wrote: > Björn Lindberg wrote: > > Mirko <mirko.vuko...(a)gmail.com> writes: > > >> I had no idea nreverse could reach this deep (amounting to shallow > >> understanding/thinking?). > > >> This is the code snippet: > > >> (let ((data (tecplot-data data-pod var :type :boundary :avg avg))) > >> (coerce (reverse data) 'vector))) > > > In this particular case, the perhaps obvious solution is to reverse > > (heh) the order of the reversal and the coercion: > > > (nreverse (coerce data 'vector)) > > Also dangerous, in case data is already a vector (and you don't know > whether it is one or not because you may change the other parts of your > program later). > > The general rule applies: Only use optimizations if you know they > actually buy you something. A slight variant of this rule is: Only use > destructive operations on conses when they have been created in the same > function, or the other function that returns them gives strong > guarantees about their 'freshness'. When in doubt, opt for > non-destructive operations. > > Pascal > > -- > My website:http://p-cos.net > Common Lisp Document Repository:http://cdr.eurolisp.org > Closer to MOP & ContextL:http://common-lisp.net/project/closer/ That is one reason for my original post -- (other than to warn those that have been warned, and still chose to ignore the warning): elicit some rules on when it may be OK to use destructive operations. Thanks to all.
From: vippstar on 8 Dec 2009 14:04 On Dec 8, 7:53 pm, Kaz Kylheku <kkylh...(a)gmail.com> wrote: > One day, a student came to moon with a brilliant idea. ``If we just add > a reference count field to conses, we can make NREVERSE behave like > REVERSE when the count is greater than one ... '' > > To which Moon replied: > > [ Everyone: insert your best completion of the story here. ] Pretending to be a destructive function when you are not one is crippling valid code, such as (let* ((l1 (list 1 2 3)) (l2 l1)) (nreverse l1) l2) Moon in all probability replied that he's busy not wasting his time taking the blade out of the knife to make sure people won't cut themselves while using it.
From: vippstar on 9 Dec 2009 03:07
On Dec 9, 3:06 am, t...(a)sevak.isi.edu (Thomas A. Russ) wrote: > vippstar <vipps...(a)gmail.com> writes: > > Pretending to be a destructive function when you are not one is > > crippling valid code, such as > > (let* ((l1 (list 1 2 3)) > > (l2 l1)) > > (nreverse l1) l2) > > I don't think this really counts as deterministic, portable code under > the standard. It is just not predictable what this will return. And > anything it does return will be allowed by the standard, even when > destructive operations are used. The ability to BE destructive does not > REQUIRE that the respective operations be performed in place. That is > why one must ALWAYS use the return value of the destructive operation > and not rely on in-place effects. > > Among the results that I might plausibly expect implementations to > return for this are > > (1 2 3) ; NREVERSE can be implemented by REVERSE > (1) ; The CDRs of cells are just re-arranged > > In fact, I would be a bit surprised if any implementations actually > returned what I think you hoped for, namely > > (3 2 1) > > I would expect that (1) is the most likely result. Let's do some > testing: > > LispWorks 5.1: (1) > CCL 1.3 (1) > CLisp 2.47 (3 2 1) ; OK, I'm surprised! > SBCL 1.0.30 (1) > CMUCL 19e (1) > ABCL 0.17.0 (3 2 1) ; More surprises > ACL 7.0 (1) > > BTW, a more interesting version for comparison would be > > (let* ((l1 (list 1 2 3)) > (l2 l1)) > (values (nreverse l1) l2)) If we name the conses of this three-element list as A, B and C, NREVERSE guarantees the contents of the list will be (3 2 1), but it doesn't guarantee the order of conses will be A B C, or C B A. The implementations that provided surprising results returned CBA, while the rest return ABC, implementations could return any combination of the conses that made up the list. But why is it undefined? I haven't understood that. You could say that l2 could have any value after NREVERSE was called depending on the implementation, thus why it is undefined - but l2 is bound to the same cons cell. I could answer that no conforming NREVERSE implementation could have l2 a value different than (3 2 1) (2 1) (1). Isn't that also true? Also, isn't it true that l2 could never be (1 2 3)? But that'd be the case with the NREVERSE suggestion in the student example, which is why (1 2 3) for l2 isn't conforming. |