* Why doesn't nconc change my variable? @ 2014-10-05 1:36 Marcin Borkowski 2014-10-05 1:58 ` Drew Adams 0 siblings, 1 reply; 13+ messages in thread From: Marcin Borkowski @ 2014-10-05 1:36 UTC (permalink / raw To: help-gnu-emacs@gnu.org Hi list, I don't get it. (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? Best, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Adam Mickiewicz University ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable? 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 [not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org> 0 siblings, 2 replies; 13+ messages in thread From: Drew Adams @ 2014-10-05 1:58 UTC (permalink / raw To: Marcin Borkowski, help-gnu-emacs > (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). 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)) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? 2014-10-05 1:58 ` Drew Adams @ 2014-10-05 9:54 ` Marcin Borkowski 2014-10-05 10:52 ` Thorsten Jolitz 2014-10-05 16:29 ` Drew Adams [not found] ` <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org> 1 sibling, 2 replies; 13+ messages in thread From: Marcin Borkowski @ 2014-10-05 9:54 UTC (permalink / raw To: help-gnu-emacs 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 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? 2014-10-05 9:54 ` Marcin Borkowski @ 2014-10-05 10:52 ` Thorsten Jolitz 2014-10-05 16:29 ` Drew Adams 1 sibling, 0 replies; 13+ messages in thread From: Thorsten Jolitz @ 2014-10-05 10:52 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: >>> (setq my-list (nconc my-list '("wtf"))) > That I didn't read earlier; I've read it now, and still don't get it. even w/o understanding the details, one can simply try to internalize the rule that after destructive list operations a setq is necessary to make changes take effect, i.e. always use this (pseudo-code) pattern: ,---- | (setq X (destuctively-modify X)) `---- -- cheers, Thorsten ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable? 2014-10-05 9:54 ` Marcin Borkowski 2014-10-05 10:52 ` Thorsten Jolitz @ 2014-10-05 16:29 ` Drew Adams 2014-10-05 16:38 ` Drew Adams 1 sibling, 1 reply; 13+ messages in thread From: Drew Adams @ 2014-10-05 16:29 UTC (permalink / raw To: Marcin Borkowski, help-gnu-emacs > 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 general. 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 structures. 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. ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: Why doesn't nconc change my variable? 2014-10-05 16:29 ` Drew Adams @ 2014-10-05 16:38 ` Drew Adams 0 siblings, 0 replies; 13+ messages in thread From: Drew Adams @ 2014-10-05 16:38 UTC (permalink / raw To: Marcin Borkowski, help-gnu-emacs > 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. Sorry, those parens were misplaced. Should be this: 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). ^ permalink raw reply [flat|nested] 13+ messages in thread
[parent not found: <mailman.10475.1412502895.1147.help-gnu-emacs@gnu.org>]
* Re: Why doesn't nconc change my variable? [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 2 siblings, 0 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 18:12 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > 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.) You did not. Your experience was wrong or incomplete. (setf print-circle t) (defun strange (list) (nconc list '("wtf"))) (strange (strange (list 1 2 3))) --> (1 2 3 . #1=("wtf" . #1#)) (setf print-circle nil print-length 15 eval-expression-print-length 15) (defun strange (list) (nconc list '("wtf"))) ; you need to redefine it. (strange (strange (list 1 2 3))) --> (1 2 3 "wtf" "wtf" "wtf" . #3) Actually, if you try to call strange^3, it falls into an infinite loop, because after strange^2, "wtf" is in a circular list. Again, do not mix immutable data with mutable data, if you want to mutate the result later! Use: (nconc list (list "wtf")), not quote. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? [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 2 siblings, 0 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 18:14 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > 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, NO! There is no pointer in lisp! An empty list is the symbol nil! (symbolp (list)) --> t (consp (list)) --> nil (symbol-name (list)) --> "nil" (symbolp (list 1)) --> nil (consp (list 1)) --> t (car (list 1)) --> 1 (cdr (list 1)) --> nil -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? [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 2 siblings, 0 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 18:31 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > (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.) Instead, look at the lisp source! ;-) (defun .nconc (&rest lists) (let ((lists (do ((curlists lists (rest lists))) ((or (null curlists) (first curlists)) curlists)))) (when lists (let ((current (first lists))) (dolist (next (rest lists) (when next (setf (cdr (last current)) next current next))))))) (.nconc (list 1 2 3) (list 4 5 6) (list 7 8 9)) --> (1 2 3 4 5 6 7 8 9) (.nconc (list 1 2 3) nil (list 4 5 6)) --> (1 2 3 4 5 6) (.nconc (list 1 2 3) nil) --> (1 2 3) (.nconc nil (list 1 2 3)) --> (1 2 3) (.nconc nil) --> nil > 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? Yes. > 2. Do I get it correctly that what Pascal called "a nil symbol" is just > NUL under the hood? No. > 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.) If they're eq then there's no difference. It's the lisp reader that reads () as nil: (car (read-from-string "()")) --> nil (car (read-from-string "nil")) --> nil (car (read-from-string "(list)")) --> (list) It's the lisp evaluator that calls list and have it return nil, just like nil, since nil is bound to nil: (symbol-value 'nil) --> nil (eval 'nil) --> nil (eval '(list)) --> nil > 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'?) (setf list (nconc list (list new-element))) > 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)? Your above was wrong, so no. ;-) I guess these things are explained more pedagogically in (info "(eintr)") and notably in (info "(eintr) List Implementation") -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
[parent not found: <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org>]
* Re: Why doesn't nconc change my variable? [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 18:04 ` Pascal J. Bourguignon 1 sibling, 2 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 1:59 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > Hi list, > > I don't get it. > > (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? () is actually read as the symbol nil. Symbols are symbols, and not cons cells. You cannot transform a symbol into a cons cell. It is impossible for any function to transform nil into a cons cell. And vice-versa, it is impossible to transform a cons cell into a symbol such as nil. This is the reason why you should also use setf when deleting elements from a list: (setf list (delete e list)) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? 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> 1 sibling, 0 replies; 13+ messages in thread From: Marcin Borkowski @ 2014-10-05 9:35 UTC (permalink / raw To: help-gnu-emacs On 2014-10-05, at 03:59, Pascal J. Bourguignon wrote: > Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > >> Hi list, >> >> I don't get it. > > () is actually read as the symbol nil. > Symbols are symbols, and not cons cells. > You cannot transform a symbol into a cons cell. > It is impossible for any function to transform nil into a cons cell. > > And vice-versa, it is impossible to transform a cons cell into a symbol > such as nil. This is the reason why you should also use setf when > deleting elements from a list: > > (setf list (delete e list)) I still don't understand. What if I used (list) to generate an empty list instead of () or nil? The results seem to be still the same. Best, -- Marcin Borkowski http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski Adam Mickiewicz University ^ permalink raw reply [flat|nested] 13+ messages in thread
[parent not found: <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org>]
* Re: Why doesn't nconc change my variable? [not found] ` <mailman.10474.1412501757.1147.help-gnu-emacs@gnu.org> @ 2014-10-05 17:50 ` Pascal J. Bourguignon 0 siblings, 0 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 17:50 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > On 2014-10-05, at 03:59, Pascal J. Bourguignon wrote: > >> Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: >> >>> Hi list, >>> >>> I don't get it. >> >> () is actually read as the symbol nil. >> Symbols are symbols, and not cons cells. >> You cannot transform a symbol into a cons cell. >> It is impossible for any function to transform nil into a cons cell. >> >> And vice-versa, it is impossible to transform a cons cell into a symbol >> such as nil. This is the reason why you should also use setf when >> deleting elements from a list: >> >> (setf list (delete e list)) > > I still don't understand. What if I used (list) to generate an empty > list instead of () or nil? The results seem to be still the same. The function list returns nil or a cons. When it's given no argument, like in (list), it returns nil. When it's given N arguments, with N>=1, then it returns N new conses, cdr-linked, with each argument in order stored in the car slots. So if you used (list) it would make no difference, you'd have to store the result of delete or of nconc to the variable: (setf list (delete 42 (list))) (let ((list (list))) (setf list (nconc list (list 42))) list) -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: Why doesn't nconc change my variable? [not found] <mailman.10460.1412473030.1147.help-gnu-emacs@gnu.org> 2014-10-05 1:59 ` Pascal J. Bourguignon @ 2014-10-05 18:04 ` Pascal J. Bourguignon 1 sibling, 0 replies; 13+ messages in thread From: Pascal J. Bourguignon @ 2014-10-05 18:04 UTC (permalink / raw To: help-gnu-emacs Marcin Borkowski <mbork@wmi.amu.edu.pl> writes: > Hi list, > > I don't get it. > > (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"))) Also, you are doing something dangerous here: You are mixing mutable and immutable data. This is dangerous, because now you may believe that your variable contains mutable data, and try to mutate it, and you will actually try to mutate immutable data, (which has usually strange or catastrophic results). (defvar my-list) (setq my-list (list 1 2 3)) ;; now, my-list contains mutable data. You can modify the car or ;; the cdr of any cell in the list. (setq my-list (nconc my-list '("wtf"))) ;; Now, my-list is bound to the list: (1 2 3 "wtf") ;; but this list is made of 3 mutable cons cells, and one immutable ;; cons cell, with one immutable string! If you were to perform any of: (setq my-list (nconc my-list '("bad"))) (setq my-list (car (last my-list) "bad")) (setq (aref (car (last my-list)) 0) ?W) (setq my-list (delete* "wtf" my-list :test (function string=))) ;; etc. you would get strange/catastrophical results: For example, try: (defun strange (list) (nconc list '("wtf"))) (let ((a (strange (list 1 2 3)))) (setf (car (last a)) "BAD") (list a (strange (list 4 5 6)))) --> ((1 2 3 "BAD") (4 5 6 "BAD")) ; WTF, where is "wtf"? If you try with: (setf print-circle t) (let ((a (strange (list 1 2 3)))) (setf (car (last a)) "strange") (list a (strange (list 4 5 6)))) --> ((1 2 3 . #1=("strange")) (4 5 6 . #1#)) this may give you a hint of what's happening. So avoid mixing mutable and immutable data, or consider the result to be immutable (and therefore avoid using destructive operations on it). Notice that append, while it copies the N-1 first arguments, it keeps the last argument, so (append list '("wtf")) is no better than (nconc list '("wtf")). You need (nconc list (list 'wtf)) ; if you want immutable elements or (nconc list (list (format "%s" "wtf"))) ; if you want ; mutable elements. -- __Pascal Bourguignon__ http://www.informatimago.com/ “The factory of the future will have only two employees, a man and a dog. The man will be there to feed the dog. The dog will be there to keep the man from touching the equipment.” -- Carl Bass CEO Autodesk ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2014-10-05 18:31 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 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 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
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.