From: Sam Steingold
Subject: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89
Date: 
Message-ID: <m3iu8xqd6j.fsf@eho.eaglets.com>
REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89 (ANSI CL issue 293) says that

 (NRECONC list tail)
  is constrained to have side-effect behavior equivalent to:
  (NCONC (NREVERSE list) tail).

The question is: should it be equivalent according to the minimal
requirements of the ANSI spec or according to the implementation?

E.g., suppose an implementation makes sure that (eq x (nreverse x)) is
always T (like CLISP does):

cl-user[47]: > (setq z (list 1 2 3))
(1 2 3)
cl-user[48]: > (nreverse z)
(3 2 1)
cl-user[49]: > z
(3 2 1)

ANSI doesn't require this, and doesn't forbid it either, so this is
compliant.  Now, 

cl-user[51]: > (nconc (nreverse z) y)
(1 2 3 4 5 6)
cl-user[52]: > z
(1 2 3 4 5 6)
cl-user[53]: > (setq z (list 3 2 1))
(3 2 1)
cl-user[54]: > (nreconc z y)
(1 2 3 4 5 6)
cl-user[55]: > z
(3 4 5 6)

I.e., Z is different after `nreconc' and after `nconc/nreverse'.

The question is, is the implementation required to be as smart about
`nreconc' as it is about `nreverse'?

In other words, when the spec says the above, does it mean "(NCONC
(NREVERSE list) tail)" in this implementation or "(NCONC (NREVERSE list)
tail)" in a minimally complying implementation?

Thanks.

-- 
Sam Steingold (http://www.goems.com/~sds) running RedHat6.0 GNU/Linux
Micros**t is not the answer.  Micros**t is a question, and the answer is Linux,
(http://www.linux.org) the choice of the GNU (http://www.gnu.org) generation.
main(a){printf(a,34,a="main(a){printf(a,34,a=%c%s%c,34);}",34);}

From: Kent M Pitman
Subject: Re: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89
Date: 
Message-ID: <sfwu2sh6n2b.fsf@world.std.com>
Sam Steingold <···@goems.com> writes:

> The question is, is the implementation required to be as smart about
> `nreconc' as it is about `nreverse'?

I think when you do a destructive operation, you should assume that
you have the only pointer to that element or any of its relevant
subcomponents and that if someone else does, it's their problem.  If
you (nreconc x y), I think you should assume that any other pointers
to x or its subtails are destroyed.  That is, you should always, as a
programmer, assume a minimum of guarantees from the system.

In practice, I'll be interested to hear if you have a reason to use
NRECONC other than implementing the dotted reader for reading
(FOO . BAR) or (FOO BAR . BAZ), which is the only code I've ever personally
written that uses NRECONC.
From: Sam Steingold
Subject: Re: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89
Date: 
Message-ID: <m3aeu8qj85.fsf@eho.eaglets.com>
>>>> In message <···············@world.std.com>
>>>> On the subject of "Re: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89"
>>>> Sent on Wed, 9 Jun 1999 22:12:12 GMT
>>>> Honorable Kent M Pitman <······@world.std.com> writes:
 >> Sam Steingold <···@goems.com> writes:
 >> 
 >> > The question is, is the implementation required to be as smart about
 >> > `nreconc' as it is about `nreverse'?
 >> 
 >> I think when you do a destructive operation, you should assume that
 >> you have the only pointer to that element or any of its relevant
 >> subcomponents and that if someone else does, it's their problem.  If
 >> you (nreconc x y), I think you should assume that any other pointers
 >> to x or its subtails are destroyed.  That is, you should always, as
 >> a programmer, assume a minimum of guarantees from the system.

I am sorry I was not clear on the issue.  I was asking the question as
an IMPLEMENTOR, not as a USER.  (As a user, I don't rely on these
implementation-specific features anyway).

My question is: do we have to be as smart about `nreconc' as we are
about `nreverse' to be able to claim ANSI compliance on
REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89?

 >> In practice, I'll be interested to hear if you have a reason to use
 >> NRECONC

I have never used `nreconc'.

-- 
Sam Steingold (http://www.goems.com/~sds) running RedHat6.0 GNU/Linux
Micros**t is not the answer.  Micros**t is a question, and the answer is Linux,
(http://www.linux.org) the choice of the GNU (http://www.gnu.org) generation.
cogito cogito ergo cogito sum
From: Barry Margolin
Subject: Re: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89
Date: 
Message-ID: <kDQ73.502$KM3.144193@burlma1-snr2>
In article <··············@eho.eaglets.com>,
Sam Steingold  <···@goems.com> wrote:
>My question is: do we have to be as smart about `nreconc' as we are
>about `nreverse' to be able to claim ANSI compliance on
>REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89?

I believe that the standard is only referring to the minimal required
behavior, not the implementation-specific behavior.

Applying common sense, I don't see how it could be otherwise.  How could a
program tell if you didn't do this?  Just because NREVERSE is usually smart
doesn't mean that it always is.  The following would be valid
implementations of NREVERSE and NRECONC:

(defun nreverse (list)
  (if (zerop (random 1000000))
      (reverse list)
      (destructive-reverse list)))

(defun nreconc (list thing)
  (nconc (nreverse list) thing)

This clearly conforms to the more constrained specification that you're
asking about, but it will be impossible for a program to tell because
they're both non-deterministic in regard to destructivity and reuse.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: nreconc, nreverse, and REMF-DESTRUCTION-UNSPECIFIED:X3J13-MAR-89
Date: 
Message-ID: <sfwaeu6vngp.fsf@world.std.com>
Barry Margolin <······@bbnplanet.com> writes:

> (defun nreverse (list)
>   (if (zerop (random 1000000))
>       (reverse list)
>       (destructive-reverse list)))

Strange as this sample implementation of Barry's is, I was going to
suggest virtually the identical technique for demonstrating pretty
much the same claim as Barry has made here: Implementations have more
latitude than they typically use.   And users often conclude very
unwarranted amounts of information from extremely small datasets on
data they have no way of knowing is statistically representative.

It is for this reason that we recommend programmers program
conservatively.  If we didn't want implementors to be creative, we
would have nailed the definitions down much more precisely in the
spec.  The whole idea is that the vendor has a major responsibility
to be efficient in ways we could not anticipate/specify, so we had
to leave "wiggle room" for vendors to use in changing their 
implementation without breaking user programs.  This can't work if
users are allowed to assume vendors will never exploit the extra
flexibility that is reserved to vendors.  If users could depend on
these things, we'd have to change the standard every time  a new
optimization was invented or every time a vendor came along who
wanted to use a new implementation technique.  That would be awful.