From: Peter Seibel
Subject: nbutlast reliably destructive?
Date: 
Message-ID: <m3oeu7bc3i.fsf@javamonkey.com>
In the dictionary entry for NBUTLAST in the standard it says:

  "nbutlast is like butlast, but nbutlast may modify list. It changes
  the cdr of the cons n+1 from the end of the list to nil."

In practice how do folks (implementors in particular) interpret the
"may modify" vs the more definitive "it changes". Can we rely on
NBUTLAST to always set the cdr? I.e. is this equivalence true:

  (nbutlast list n) === (setf (cdr (last list (1+ n))) nil)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Will Hartung
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <brqj7e$6da3m$1@ID-197644.news.uni-berlin.de>
"Peter Seibel" <·····@javamonkey.com> wrote in message
···················@javamonkey.com...
>
> In the dictionary entry for NBUTLAST in the standard it says:
>
>   "nbutlast is like butlast, but nbutlast may modify list. It changes
>   the cdr of the cons n+1 from the end of the list to nil."
>
> In practice how do folks (implementors in particular) interpret the
> "may modify" vs the more definitive "it changes". Can we rely on
> NBUTLAST to always set the cdr? I.e. is this equivalence true:
>
>   (nbutlast list n) === (setf (cdr (last list (1+ n))) nil)

No, you can't rely on it. That's why it says "nbutlast MAY modify list".

That's the way I interpret it.

This goes back to the basic argument of not using destructive operations for
side effects.

Regards,

Will Hartung
(·····@msoft.com)
From: Barry Margolin
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <barmar-F04B55.16555817122003@netnews.attbi.com>
In article <··············@javamonkey.com>,
 Peter Seibel <·····@javamonkey.com> wrote:

> In the dictionary entry for NBUTLAST in the standard it says:
> 
>   "nbutlast is like butlast, but nbutlast may modify list. It changes
>   the cdr of the cons n+1 from the end of the list to nil."
> 
> In practice how do folks (implementors in particular) interpret the
> "may modify" vs the more definitive "it changes". Can we rely on
> NBUTLAST to always set the cdr? I.e. is this equivalence true:
> 
>   (nbutlast list n) === (setf (cdr (last list (1+ n))) nil)

I believe that was the intent -- it should be deterministic like NCONC.

The reason for the "may" wording was probably to handle the edge cases.  
E.g. when n=0, it changes changes the cdr of the last cons to nil, but 
it already was nil so there's no real change.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
From: Kent M Pitman
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <sfwzndr3usq.fsf@shell01.TheWorld.com>
Barry Margolin <······@alum.mit.edu> writes:

> In article <··············@javamonkey.com>,
>  Peter Seibel <·····@javamonkey.com> wrote:
> 
> > In the dictionary entry for NBUTLAST in the standard it says:
> > 
> >   "nbutlast is like butlast, but nbutlast may modify list. It changes
> >   the cdr of the cons n+1 from the end of the list to nil."
> > 
> > In practice how do folks (implementors in particular) interpret the
> > "may modify" vs the more definitive "it changes". Can we rely on
> > NBUTLAST to always set the cdr?

No.

> > I.e. is this equivalence true:
> > 
> >   (nbutlast list n) === (setf (cdr (last list (1+ n))) nil)
 
No.

> I believe that was the intent -- it should be deterministic like NCONC.
> 
> The reason for the "may" wording was probably to handle the edge cases.  
> E.g. when n=0, it changes changes the cdr of the last cons to nil, but 
> it already was nil so there's no real change.

This rationale can't really be so since the edge cases to which you allude
are already separately enumerated in the text.

I wasn't going to reply to this at all, hoping the answer was obvious.
But if Barry has responded as he has above, I see it's not obvious.  Hmm.

I totally disagree that this is like NCONC where you are intended to use
it for side-effect.  If it were, it would say so.

Here's the reply I had written and initially discarded without sending
since it seemed at the time it was unnecessary... 

- - Cut here - - - - - 8< - - - - - - - - - - 8< - - - - - Cut here - - 

The text following this paragraph should just not be necessary, since
even if there were no examples of this, you should still believe that
"may" gives permission and "must" gives requirement.  Deciding to
confuse these is an inutterably ridiculous course of action that just
invites a problem where none needs to be.  What possible decision
could you reasonably make differently if everyone responding said
"Yes" instead of "No" to the above questions?  I claim "none", and that
this is a useless, bordering on dangerous, kind of question to ask.

- - - -

I believe there as at least one implementation in the past that
didn't implement a bunch of the destructive operations, using
instead the non-destructive ones.  That is, doing things like:

 (setf (symbol-function 'nbutlast) (symbol-function butlast))

This is a conforming definition.  It is up to the market whether it is
a "good" definition, but it permits vendors to have a small footprint
if they need to.  And, for some situations, a small filesystem footprint
may be the most important thing...  That's why the standard leaves
flexibility.

Also, independently of the notion of a small footprint, there can 
conceivably also situations in which a "full-featured" (or whatever you
want to call it) implementation might have the notion of "immutable"
data that is enforced by putting the data in read-only space of some kind.
Rather than signal an error, such an implementation might back out and call
the non-consing version. (I'm not even sure if it's permitted, as the
definition is written, to signal an error in the case of read-only data.
Such data is beyond the scope of ANSI CL, so it's something of a judgment
call.  It's just not clear whether "permission to modify" means "permission
to attempt to modify something that can't be and then to complain when it
doesn't work"...)

Bottom line?
  May means may.  Must means must.  Don't rely on things not promised.
From: james anderson
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <3FE10B8C.F4BD15CC@setf.de>
Kent M Pitman wrote:
> 
> ...
> 
> > > I.e. is this equivalence true:
> > >
> > >   (nbutlast list n) === (setf (cdr (last list (1+ n))) nil)
> 
> No.
> 
> > I believe that was the intent -- it should be deterministic like NCONC.
> >
> > The reason for the "may" wording was probably to handle the edge cases.
> > E.g. when n=0, it changes changes the cdr of the last cons to nil, but
> > it already was nil so there's no real change.
> 
> This rationale can't really be so since the edge cases to which you allude
> are already separately enumerated in the text.
> 
> I wasn't going to reply to this at all, hoping the answer was obvious.
> But if Barry has responded as he has above, I see it's not obvious.  Hmm.

it is not obvious. there is more than one confused reader. the cases in the
example passage could well be interpreted to demonstrate that the operator is
necessarily destructive. in particular, one example is careful to pass a
non-constant argument.

> 
> I totally disagree that this is like NCONC where you are intended to use
> it for side-effect.  If it were, it would say so.

this reader has, until now, thought that it did say so. in particular, the
qualifying text which accompanies other potentially destructive operators is
not present in this case. in light of the examples, the "may" has, until now,
been understood to apply to the case where count exceeded the list length.

> 
> Here's the reply I had written and initially discarded without sending
> since it seemed at the time it was unnecessary...
> 
> ...
>
> Also, independently of the notion of a small footprint, there can
> conceivably also situations in which a "full-featured" (or whatever you
> want to call it) implementation might have the notion of "immutable"
> data that is enforced by putting the data in read-only space of some kind.
> Rather than signal an error, such an implementation might back out and call
> the non-consing version.

doesn't this argument apply to any destructive operator. while nbutlast isn't
mentioned in the constant-modification discussion, other potentially
destructive operators are absent there as well.

>   (I'm not even sure if it's permitted, as the
> definition is written, to signal an error in the case of read-only data.
> Such data is beyond the scope of ANSI CL, so it's something of a judgment
> call.  It's just not clear whether "permission to modify" means "permission
> to attempt to modify something that can't be and then to complain when it
> doesn't work"...)


> 
> Bottom line?
>   May means may.  Must means must.  Don't rely on things not promised.

this runs both ways.
if the intent were to not promise, then the text could have been

nbutlast is like butlast, but nbutlast may modify list. It [may change] the
cdr of the cons n+1 from the end of the list to nil[, or it may return a copy
of the sublist of list which ends with that cons.]

...
From: Bob Riemenschneider
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <ce15782d.0312191803.74861a16@posting.google.com>
james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> 
> ... nbutlast is like butlast, but nbutlast may modify list. It [may change] the
> cdr of the cons n+1 from the end of the list to nil[, or it may return a copy
> of the sublist of list which ends with that cons.]

The standard *could* have said that, but that's more restrictive than
what the standard *does* say: reusing some of the conses and not
others would also be conforming (tho' I can't imagine why one would
want to do such a thing).

But, more importantly, how would your proposal be an improvement over
"don't rely on it copying, and don't rely on it being destructive --
we want to leave  implementors maximal freedom, subject to the
constraint that the result must be EQUAL to what BUTLAST would
return"?

                                                            -- rar
From: Peter Seibel
Subject: Re: nbutlast reliably destructive?
Date: 
Message-ID: <m3zndq9fcq.fsf@javamonkey.com>
Kent M Pitman <······@nhplace.com> writes:

> Barry Margolin <······@alum.mit.edu> writes:
> 
> > In article <··············@javamonkey.com>,
> >  Peter Seibel <·····@javamonkey.com> wrote:
> > 
> > > In the dictionary entry for NBUTLAST in the standard it says:
> > > 
> > >   "nbutlast is like butlast, but nbutlast may modify list. It changes
> > >   the cdr of the cons n+1 from the end of the list to nil."
> > > 
> > > In practice how do folks (implementors in particular) interpret the
> > > "may modify" vs the more definitive "it changes". Can we rely on
> > > NBUTLAST to always set the cdr?

[snip]

> > I believe that was the intent -- it should be deterministic like NCONC.
> > 
> > The reason for the "may" wording was probably to handle the edge cases.  
> > E.g. when n=0, it changes changes the cdr of the last cons to nil, but 
> > it already was nil so there's no real change.
> 
> This rationale can't really be so since the edge cases to which you
> allude are already separately enumerated in the text.

Hmmm. I don't see that, assuming you're talking about something in the
dictionary entry for butlast/nbutlast. The special case I see
mentioned is when (> n (length list)):

  If there are fewer than n conses in list, nil is returned and, in
  the case of nbutlast, list is not modified.

It doesn't say anything about the case Barry mentioned, when n=0.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp