[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: Why doesn't nconc change my variable?

From: Drew Adams
Subject: RE: Why doesn't nconc change my variable?
Date: Sun, 5 Oct 2014 09:29:12 -0700 (PDT)

> 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?

Yes.  That's exactly what it means.  "Destructive" operations
are _potentially_ destructive of existing data.  That label is
just shorthand, to contrast with nondestructive operations that
do not modify data.  It's about functions that you use for their
side effects and not just their values.

> 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?

There is no "canonical" way.  Use `append' if you want to return
a new list that is a copy (but not a deep copy) of the original
list but with an additional element at the end.

Use `nconc' if you want to obtain a list that has the additional
element at the end, and you don't care about preserving the
original list as it was.  The list you obtain _might or might
not_ share some structure with the argument lists.

A good guideline is to _not_ use "destructive" operations, in

When there are use cases where you really might be able to take
advantage of them _you will know it_.  Another way to put this is
that you need to really understand and be comfortable with side
effects before you try to make real use of  them.  Most of the
time you can (and should) avoid them (at least those that modify
list structure etc.) - and not have to worry about them.

If you do want to start experimenting with list-structure
modification then another guideline is to use "destructive"
operations only on a new list (new cons cell) that you have
assigned to only one variable.  IOW, create a new list and
play with that.  And do not assign any variables to any parts of
that list structure.  Do not use destructive operations on an
existing list from someone else's code, or even from your code,
if you are not sure what you are doing.

Later, you might relax that second guideline: part of the point
of using list-modification operations is to _share_ list
structure (have different variables point, directly or
indirectly) to the same cons cell.  But this is not something
to be trifled with.  It is not easy to follow or debug program
logic when it starts fiddling with list structure and dependent

Anyway, what you are not quite understanding so far, I think,
(but you seem to be getting closer), is just what a Lisp
_variable_ is, including how it relates to its value.

1. A variable is a Lisp _symbol_ that is associated with a
   value at a given moment.

2. That value could be a cons (so that the value is a non-empty
   list or a dotted list).

3. A cons that might be the value of a variable has an
   *independent* existence from the variable's symbol.  The
   symbol is mapped to its value.  Function `symbol-value'
   returns the value.

  a. It is possible to change the value of the variable (i.e.,
     change the association, so that the `symbol-value' of the
     symbol points to something different.

  b. It is also possible to not change that association (mapping,
     binding) between symbol and cons-cell value, but to change
     the car or cdr of the cons cell itself.  This has the
     indirect effect of changing the value: the thing that is
     the value changes, instead of the variable binding changing.

4. If something changes the car or cdr of the cons cell value
   of a variable, this changes the variable value.  It still points
   to the same cons cell, but the content of that cell is not the
   same as it was.

5. A "destructive" "function" such as `nconc' _might or might not_
   change a cons in one of its arguments.  Typically, the function
   is used for its side effects.  But typically also, the _result_
   returned by the function is the cons that is the main side-effect
   goal.  For `nconc', for example, the return value is the list
   resulting from the append/concatenate operation.  That returned
   list (for `nconc') might or might not share structure with
   one of the arguments.

6. Regardless of whether a given destructive function does in
   fact change a cons in one of its arguments, it does _not_
   fiddle with the mapping between any symbols and any conses.

   IOW, it does not reassign or rebind any variables.  Typically,
   the function _sees no variables_ at all.  It receives only
   cons (or nil) _values_ as its arguments.  It has no way of
   knowing (and it does not care) about some variable that you
   might have assigned or bound to one of the conses that it
   looks at and might modify.  That variable is your affair -
   your responsibility, not the function's.

7. (Again) If you have a variable that has a value that is a cons,
   and if that cons is modified, then the variable still points to
   it, i.e., it points to the updated value.  Modifying that cons
   has the indirect side effect of modifying the variable value.

8. If you have a variable that has a value that is a cons, and if
   you call a function that does _not_ modify that cons (i.e., no
   modification of any part of it - e.g., any part of a cons chain
   reached from its car or its cdr), then the variable value is
   _not_ changed.

9. #8 includes the case where you call a "destructive" function
   that might change something else (e.g. another cons cell, not
   reached from the cons pointed to by the variable).  The variable
   value is _not_ changed.

10. #9 is relevant even if the function _returns_ a different cons,
   which represents the intended _result_ of the operation.  The
   variable does _not_ point to this other cons.  If the cons
   pointed to by the variable is not, itself, changed, then the
   variable value is not changed (by the operation).  The variable
   still points to the same cons - nothing about the function
   changes what the variable points to.

11. So yes, if the _result_ returned by the operation is what
   you want the variable value to be (and it typically is), then
   it is up to you to reassign the variable value to it.  IOW,
   use `setq' to update the variable to have the new value.

HTH.  Others will no doubt state all or most of this more
briefly, e.g. using some simple code examples to make it clear.
The description above is intentionally somewhat repetitive.
If it helps, fine.  If not, sorry.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]