all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Marcin Borkowski <mbork@wmi.amu.edu.pl>
To: help-gnu-emacs@gnu.org
Subject: Re: Why doesn't nconc change my variable?
Date: Sun, 05 Oct 2014 11:54:24 +0200	[thread overview]
Message-ID: <87vbnylu3z.fsf@wmi.amu.edu.pl> (raw)
In-Reply-To: <3867d7c2-936d-4441-91d6-3b12dc959391@default>


On 2014-10-05, at 03:58, Drew Adams wrote:

>> (setq my-list ())
>> (nconc my-list '("wtf"))
>> 
>> and my-list is still nil.  If, OTOH, I do
>> (setq my-list ())
>> (setq my-list (nconc my-list '("wtf")))
>> 
>> my-list is ("wtf").
>> 
>> Why is that so?  I though nconc is supposed to change all its
>> arguments but the last one.  Is the latter construct a correct
>> way of adding an element at the end of the list?
>
> No, it's not supposed to do that. You discovered just what it
> does do.  And you could have discovered it earlier by reading
> some doc.  See the Elisp manual, node `Rearrangement' (found by
> doing `i nconc' in the manual).

I did read it.  And a few times, for that matter.

You see, one of the worst intellectual mistakes you can make is to have
a wrong mental model of something.  This seems to be the case here, and
that's why I really want to grok this issue.

> See also node `Sets and Lists', in particular this (about `delq',
> but the same idea applies to other destructive list operations):
>
>  Note that `(delq 'c sample-list)' modifies `sample-list' to splice
>  out the third element, but `(delq 'a sample-list)' does not splice
>  anything--it just returns a shorter list.  Don't assume that a variable
>  which formerly held the argument LIST now has fewer elements, or that
>  it still holds the original list!  Instead, save the result of `delq'
>  and use that.  Most often we store the result back into the variable
>  that held the original list:
>
>      (setq flowers (delq 'rose flowers))

That I didn't read earlier; I've read it now, and still don't get it.
Sorry.  (Edit: while I was writing the rest of this post, things
apparently got more clear, but I'll leave the rest, since if I'm right,
this might be (hopefully) instructive for others reading it, and I might
even want to save it to post it on my blog.)

Now I have two choices.  One is to install the C source and try to read
it.  This I cannot do now (time constraints, and while I did learn some
C, it was, what, fifteen years ago or so).  That's why I'm asking here.
Please bear with me.  This should also be good for Emacs, since it may
be the case that if I cannot understand the manual, someone else might
have troubles with that, too, so maybe the manual is buggy.

What I thought was essentially this: under the hood, a list is a pointer
(using C terminology) to a cons cell.  The car of the cons cell is a
pointer to some data (say, a string), and the cdr - a pointer to the
next cons cell.

What I thought is that if you say, e.g.,

(setq my-list ("hello" "world"))

and then

(nconc my-list '("wtf"))

then my-list points to the list ("hello" "world" "wtf").  This seems to
be indeed the case.  (And the wtf's get added if I repeat the nconc step
- I confirmed that experimentally.)

Now, when I say

(setq my-list (list))

(or (setq list ()))

then nconc'ing '("wtf")'s onto it (as before) does not have the same
effect.

Why on earth is that!?

Does it mean that Pascal's earlier response was right?  Now that I'm
thinking about it, this makes sense: an empty list is (I would guess) a
NUL pointer, so nconc'ing has not the meaning of "changing the cdr" but
rather of "returning a brand new cons cell".  This in turn means that
this sentence from the manual:

"Instead, the last CDR of each of the LISTS is changed to refer to the
following list."

is misleading: if I have an empty list, there's no cdr to change, and
that's why nconc would (probably) branch to a different subroutine and
create a brand new cons cell.

(Now that I'm wondering what the implementation might actually be, I'm
more and more tempted to look at the C source.  This is probably a good
sign.)

So, now I have some more questions and one suggestion.  (More knowledge
always brings more questions, right?)

1. Do I get it correctly that the "destructiveness" of some functions
(like nconc) does /not/ mean that they /change/ some of their arguments,
but only that they /may/ do it, and that relying on that is risky?

2. Do I get it correctly that what Pascal called "a nil symbol" is just
NUL under the hood?  Does it mean that there's no difference between (),
nil and the result of (list) (as opposed to the results of calling list
twice with the same arguments)?  (They seem to be `eq', as I've just
checked.)

3. What is the "canonical" way to append an element to a list, in the
sense that I have a variable containing (=pointing to?) a list, I want
it to point to a list one element longer?  And, while at that, what is
the "canonical" way to /prepend/ an element to a list (is it `push'?)

4. (This is the suggestion.)  If the above is right, could someone make
it more clear in the manual (or point me to the place in the manual
where it is actually stated)?

TIA,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Adam Mickiewicz University



  reply	other threads:[~2014-10-05  9:54 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-05  1:36 Why doesn't nconc change my variable? Marcin Borkowski
2014-10-05  1:58 ` Drew Adams
2014-10-05  9:54   ` Marcin Borkowski [this message]
2014-10-05 10:52     ` Thorsten Jolitz
2014-10-05 16:29     ` Drew Adams
2014-10-05 16:38       ` Drew Adams
     [not found]   ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>
2014-10-05 18:12     ` Pascal J. Bourguignon
2014-10-05 18:14     ` Pascal J. Bourguignon
2014-10-05 18:31     ` Pascal J. Bourguignon
     [not found] <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org>
2014-10-05  1:59 ` Pascal J. Bourguignon
2014-10-05  9:35   ` Marcin Borkowski
     [not found]   ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>
2014-10-05 17:50     ` Pascal J. Bourguignon
2014-10-05 18:04 ` Pascal J. Bourguignon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87vbnylu3z.fsf@wmi.amu.edu.pl \
    --to=mbork@wmi.amu.edu.pl \
    --cc=help-gnu-emacs@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.