From: Mirko on
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
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
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
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
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.