[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RE: Why doesn't nconc change my variable?
RE: Why doesn't nconc change my variable?
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
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.
Re: Why doesn't nconc change my variable?, Pascal J. Bourguignon, 2014/10/05