all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* binding question
@ 2013-10-06  9:35 Eric Abrahamsen
  2013-10-06 10:14 ` Thien-Thi Nguyen
  2013-10-06 12:39 ` Michael Heerdegen
  0 siblings, 2 replies; 5+ messages in thread
From: Eric Abrahamsen @ 2013-10-06  9:35 UTC (permalink / raw
  To: help-gnu-emacs

I've got a variable binding scenario that I thought would be easy to
resolve, but is giving me trouble. I have the feeling that this scenario
represents some sort of Lesson 1 in How Bindings Work, but I'm still not
sure of the proper solution.

The general situation is: I want to start with a list template stored in
a variable. Another function in this library starts with the template,
modifies it a few times, then does something with the modified version.

Every time this function is called, it should start with a "fresh" copy
of the template.

Clearly the following doesn't work: it actually modifies the original
list-template.

(defvar list-template
  '(item ((with . "some")
	  (sub . "lists"))
	 nil (other things will go here)))

(defun main-entry-function ()
  ;; obviously this doesn't work as defvars are always special
  (let ((list-template list-template))
  ;; list-template is accessed dynamically in the following functions
    (modify-list-template)
    (modify-list-template-again)
    (do-something-with-modified-list-template)))

The other option would be to pass list-template as an argument to each
of these functions. I guess each call would then have to look like:

(setq list-template (modify-list-template list-template))

This seems ugly, and it won't necessarily be easy to ensure the
modifying functions end by returning the new value of list-template.

What's the best way of handling this? And is there one "right" solution
for both dynamic and lexical binding?

Thanks!
Eric


PS: The wiki[1] mentions pretty much exactly my scenario, but doesn't
actually say what should be done.

[1]
http://www.emacswiki.org/emacs/DynamicBindingVsLexicalBinding#toc4




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: binding question
  2013-10-06  9:35 binding question Eric Abrahamsen
@ 2013-10-06 10:14 ` Thien-Thi Nguyen
  2013-10-06 14:03   ` Eric Abrahamsen
  2013-10-06 14:45   ` Stefan Monnier
  2013-10-06 12:39 ` Michael Heerdegen
  1 sibling, 2 replies; 5+ messages in thread
From: Thien-Thi Nguyen @ 2013-10-06 10:14 UTC (permalink / raw
  To: Eric Abrahamsen; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 755 bytes --]

() Eric Abrahamsen <eric@ericabrahamsen.net>
() Sun, 06 Oct 2013 17:35:30 +0800

   What's the best way of handling this?

Check out ‘copy-tree’, e.g.:

 (let ((list-template (copy-tree list-template)))
   ...)

See also:

 http://www.emacswiki.org/emacs/ElispCookbook

which compares ‘copy-sequence’ and ‘copy-tree’ in section "Copying".

WRT, lexical vs dynamic binding, the code is written to assume dynamic
binding, so you might want to explicitly set ‘lexical-binding’ to nil
somewhere.

-- 
Thien-Thi Nguyen
   GPG key: 4C807502
   (if you're human and you know it)
      read my lisp: (responsep (questions 'technical)
                               (not (via 'mailing-list)))
                     => nil

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: binding question
  2013-10-06  9:35 binding question Eric Abrahamsen
  2013-10-06 10:14 ` Thien-Thi Nguyen
@ 2013-10-06 12:39 ` Michael Heerdegen
  1 sibling, 0 replies; 5+ messages in thread
From: Michael Heerdegen @ 2013-10-06 12:39 UTC (permalink / raw
  To: help-gnu-emacs

Hi Eric,

in LISP, lists (cons cells) are passed by reference.  Thus, different
bindings can refer to the same list object, like here the variables a
and b:

(setq a '(1 2))

(setq b a) ; copies the reference to the list, not the list itself

(setcar a 'foo)

b

==> (foo 2)

> (defun main-entry-function ()
>   ;; obviously this doesn't work as defvars are always special
>   (let ((list-template list-template))

This creates a new local binding, but it references the same list object
in memory.  If you change the structure of the referenced object, the
change is "visible" for all variables which are bound to this object.
You can create a real copy of the object with `copy-tree'.  Or don't
destructively alter the list, but process the value with
non-destructive functions instead.

I'm sure there is a good explanation somewhere in the manual.


Regards,

Michael.




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: binding question
  2013-10-06 10:14 ` Thien-Thi Nguyen
@ 2013-10-06 14:03   ` Eric Abrahamsen
  2013-10-06 14:45   ` Stefan Monnier
  1 sibling, 0 replies; 5+ messages in thread
From: Eric Abrahamsen @ 2013-10-06 14:03 UTC (permalink / raw
  To: help-gnu-emacs

Thien-Thi Nguyen <ttn@gnu.org> writes:

> () Eric Abrahamsen <eric@ericabrahamsen.net>
> () Sun, 06 Oct 2013 17:35:30 +0800
>
>    What's the best way of handling this?
>
> Check out ‘copy-tree’, e.g.:
>
>  (let ((list-template (copy-tree list-template)))
>    ...)
>
> See also:
>
>  http://www.emacswiki.org/emacs/ElispCookbook
>
> which compares ‘copy-sequence’ and ‘copy-tree’ in section "Copying".
>
> WRT, lexical vs dynamic binding, the code is written to assume dynamic
> binding, so you might want to explicitly set ‘lexical-binding’ to nil
> somewhere.

Thanks very much to both of you! Copying sounds like exactly what I
wanted.

I was sort of wondering if there was a one-size-fits-all solution that
would also work in future lexically-bound environments, but I guess that
really would require passing arguments.

Thanks again,
Eric




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: binding question
  2013-10-06 10:14 ` Thien-Thi Nguyen
  2013-10-06 14:03   ` Eric Abrahamsen
@ 2013-10-06 14:45   ` Stefan Monnier
  1 sibling, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2013-10-06 14:45 UTC (permalink / raw
  To: help-gnu-emacs

> WRT, lexical vs dynamic binding, the code is written to assume dynamic
> binding, so you might want to explicitly set ‘lexical-binding’ to nil
> somewhere.

Better than set lexical-binding to nil is to add (defvar <foo>) at the
beginning of the file for every variable <foo> which is used via
dynamic scoping.


        Stefan




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-10-06 14:45 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-06  9:35 binding question Eric Abrahamsen
2013-10-06 10:14 ` Thien-Thi Nguyen
2013-10-06 14:03   ` Eric Abrahamsen
2013-10-06 14:45   ` Stefan Monnier
2013-10-06 12:39 ` Michael Heerdegen

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.