all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Need some education on defmacro define-toggle
@ 2009-12-28  5:16 Lennart Borgman
  2009-12-28 19:28 ` Lennart Borgman
       [not found] ` <mailman.352.1262028532.18930.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 6+ messages in thread
From: Lennart Borgman @ 2009-12-28  5:16 UTC (permalink / raw)
  To: emacs help

I just got into some trouble because of a badly written macro I
believe. After the long discussions about defmacro here I wonder if
anyone wants to help me out. How should I write the defmacro below?


I need to be able to autolad the defmacro in a little bit strange way
too. It is not a normal autoload. I want to redefine it. I do
something like:

  (defun web-autoload (fun src docstring interactive type)
  "Similar to autoload, but the SRC arg is different."
  (let ((int (when interactive '(interactive))))
    (cond
     ((eq type 'macro)
      (setq type 'defmacro))
     (t
      (setq type 'defun)))
    (eval
     `(web-autoload-1 ,fun ,src ,docstring ,int ,type))))

   (defmacro web-autoload-1 (fun src docstring interactive type)
           ....
                   (let ((the-macro (append '(,fun) args nil)))
                     (eval the-macro))
        )




Here is the troublesome macro:


(defmacro define-toggle (symbol value doc &rest args)
  "Declare SYMBOL as a customizable variable with a toggle function.
The purpose of this macro is to define a defcustom and a toggle
function suitable for use in a menu.

The arguments have the same meaning as for `defcustom' with these
restrictions:

- The :type keyword cannot be used.  Type is always 'boolean.
- VALUE must be t or nil.

DOC and ARGS are just passed to `defcustom'.

A `defcustom' named SYMBOL with doc-string DOC and a function
named SYMBOL-toggle is defined.  The function toggles the value
of SYMBOL.  It takes no parameters.

To create a menu item something similar to this can be used:

    \(define-key map [SYMBOL]
      \(list 'menu-item \"Toggle nice SYMBOL\"
            'SYMBOL-toggle
            :button '(:toggle . SYMBOL)))"
  (declare (doc-string 3))
  (list
   'progn
   (let ((var-decl (list 'custom-declare-variable
                         (list 'quote symbol)
                         (list 'quote value)
                         doc)))
     (while args
       (let ((arg (car args)))
         (setq args (cdr args))
         (unless (symbolp arg)
           (error "Junk in args %S" args))
         (let ((keyword arg)
               (value (car args)))
           (unless args
             (error "Keyword %s is missing an argument" keyword))
           (setq args (cdr args))
           (cond
            ((not (memq keyword '(:type)))
             (setq var-decl (append var-decl (list keyword value))))
            (t
             (lwarn '(define-toggle) :error "Keyword %s can't be used here"
                    keyword))))))
     (when (assoc :type var-decl) (error ":type is set.  Should not happen!"))
     (setq var-decl (append var-decl (list :type '(quote boolean))))
     var-decl)
   (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
          (SYMBOL-name (symbol-name symbol))
          (fun-doc (concat "Toggles the \(boolean) value of `"
                           SYMBOL-name
                           "'.\n"
                           "For how to set it permanently see this variable.\n"
                           ;;"\nDescription of `" SYMBOL-name "':\n" doc
                           )))
     `(defun ,SYMBOL-toggle ()
        ,fun-doc
        (interactive)
        (customize-set-variable (quote ,symbol) (not ,symbol)))
     )))




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

* Re: Need some education on defmacro define-toggle
  2009-12-28  5:16 Need some education on defmacro define-toggle Lennart Borgman
@ 2009-12-28 19:28 ` Lennart Borgman
       [not found] ` <mailman.352.1262028532.18930.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 6+ messages in thread
From: Lennart Borgman @ 2009-12-28 19:28 UTC (permalink / raw)
  To: emacs help

On Mon, Dec 28, 2009 at 6:16 AM, Lennart Borgman
<lennart.borgman@gmail.com> wrote:
> I just got into some trouble because of a badly written macro I
> believe. After the long discussions about defmacro here I wonder if
> anyone wants to help me out. How should I write the defmacro below?


I resorted to self education (which is not too bad). However I still
got problems - just on a more complicated level. The macro now looks
like this:

(defmacro define-toggle (symbol value doc &rest args)
  "Declare SYMBOL as a customizable variable with a toggle function."
  (declare   (doc-string 3)   (debug t))
  (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
         (SYMBOL-name (symbol-name symbol))
         (var-doc doc)
         (fun-doc (concat "Toggles the \(boolean) value of `" SYMBOL-name
                          "'.\nFor how to set it permanently see this
variable.\n")))
    (let ((var (append `(defcustom ,symbol ,value ,var-doc)
                args
                nil))
          (fun `(defun ,SYMBOL-toggle ()
                   ,fun-doc
                   (interactive)
                   (customize-set-variable (quote ,symbol) (not ,symbol)))))
      `(list 'progn ,var ,fun))))

This seems to work, but if the call to define-toggle already has been
done then loading a file with this define-toggle gives trouble:

Debugger entered--Lisp error: (void-variable
rngalt-display-validation-header-toggle)
  (progn rngalt-display-validation-header
rngalt-display-validation-header-toggle)
  (define-toggle rngalt-display-validation-header t "Display XML
validation headers at the top of buffer when t.\nThe validation header
is only displayed in buffers where the main\nmajor mode is derived
from `nxml-mode'." :set (lambda (sym val) (set-default sym val)
(rngalt-update-validation-header-overlay-everywhere)) :group (quote
relax-ng) :group (quote nxhtml))
  eval-buffer(#<buffer  *load*<3>> nil
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/rngalt.el" nil t)  ; Reading
at buffer position 24737
  load-with-code-conversion("c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/rngalt.el"
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/rngalt.el" t t)
  require(rngalt nil t)
  (progn (require (quote rngalt) nil t))
  (eval-and-compile (require (quote rngalt) nil t))
  eval-buffer(#<buffer  *load*<2>> nil
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-mode.el" nil t)  ;
Reading at buffer position 2959
  load-with-code-conversion("c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-mode.el"
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-mode.el" t t)
  require(nxhtml-mode nil t)
  (progn (require (quote nxhtml-mode) nil t))
  (if (fboundp (quote nxml-mode)) (progn (require ... nil t)))
  (when (fboundp (quote nxml-mode)) (require (quote nxhtml-mode) nil t))
  (progn (when (fboundp ...) (require ... nil t)))
  (eval-when-compile (when (fboundp ...) (require ... nil t)))
  eval-buffer(#<buffer  *load*> nil
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-menu.el" nil t)  ;
Reading at buffer position 3227
  load-with-code-conversion("c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-menu.el"
"c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-menu.el" nil nil)
  load("c:/emacs/p/091204/EmacsW32/nxhtml/nxhtml/nxhtml-menu.el")
  (let* ((vcs ...) (base-url ...) (rel-url ...) (base-dir ...)
(rel-url-el ...) file-url dl-file) (unless (stringp base-url) (setq
base-url ...)) (unless (stringp base-dir) (setq base-dir ...)) (setq
dl-file (expand-file-name rel-url-el base-dir)) (message "dl-file=%s"
dl-file) (unless (file-exists-p dl-file)
(web-vcs-get-missing-matching-files vcs base-url base-dir rel-url-el)
(unless ... ...)) (load dl-file) (unless (symbol-function ...) (setq
err ...)))
  (if (not (listp ...)) (let (...) (load ...) (unless ... ...)) (let*
(... ... ... ... ... file-url dl-file) (unless ... ...) (unless ...
...) (setq dl-file ...) (message "dl-file=%s" dl-file) (unless ... ...
...) (load dl-file) (unless ... ...)))
  (let* ((lib-web ...) (old-hist-elt ...) (auto-fun ...) err) (fset
(quote nxhtml-global-minor-mode) nil) (if (not ...) (let ... ... ...)
(let* ... ... ... ... ... ... ... ...)) (if (not err) (progn ... ...)
(fset ... auto-fun) (error "web-autoload: %s" err)))
  nxhtml-global-minor-mode(1)
  (let* ((util-dir ...) (related-dir ...) (nxhtml-dir ...)
(company-dir ...) (tests-dir ...)) (add-to-list (quote load-path)
nxhtml-dir) (add-to-list (quote load-path) related-dir) (add-to-list
(quote load-path) util-dir) (add-to-list (quote load-path)
nxhtml-install-dir) (add-to-list (quote load-path) company-dir)
(add-to-list (quote load-path) tests-dir) (setq
web-autoload-default-filename-element nxhtml-install-dir) (message
"... nXhtml loading %.1f seconds elapsed ..." (- ...
nxhtml-load-time-start)) (load (expand-file-name "nxhtml-loaddefs"
nxhtml-install-dir)) (message "... nXhtml loading %.1f seconds elapsed
..." (- ... nxhtml-load-time-start)) (message "Turn on
`nxhtml-global-minor-mode' unconditionally") (nxhtml-global-minor-mode
1) (message "... nXhtml loading %.1f seconds elapsed ..." (- ...
nxhtml-load-time-start)) (when (fboundp ...) (load ...)
(rncpp-patch-xhtml-loader)) (message "... nXhtml loading %.1f seconds
elapsed ..." (- ... nxhtml-load-time-start)) (load (expand-file-name
"nxhtml/nxhtml-autoload" nxhtml-install-dir)))
  (if nil nil (provide (quote nxhtml-autostart)) (if (<
emacs-major-version 23) (load ...) (let ... ...)) (let* (... ... ...
... ...) (add-to-list ... nxhtml-dir) (add-to-list ... related-dir)
(add-to-list ... util-dir) (add-to-list ... nxhtml-install-dir)
(add-to-list ... company-dir) (add-to-list ... tests-dir) (setq
web-autoload-default-filename-element nxhtml-install-dir) (message
"... nXhtml loading %.1f seconds elapsed ..." ...) (load ...) (message
"... nXhtml loading %.1f seconds elapsed ..." ...) (message "Turn on
`nxhtml-global-minor-mode' unconditionally") (nxhtml-global-minor-mode
1) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (when
... ... ...) (message "... nXhtml loading %.1f seconds elapsed ..."
...) (load ...)) (message "... nXhtml loading %.1f seconds elapsed
..." (- ... nxhtml-load-time-start)) (when nxhtml-flymake-setup
(flymake-js-load) (flymake-css-load) (flymake-java-1-load) (add-hook
... ...)) (nxhtml-list-loaded-features nil) (message "Nxml/Nxhtml
Autostart.el loaded in %.1f seconds" (- ... nxhtml-load-time-start)))
  (unless nil (provide (quote nxhtml-autostart)) (if (<
emacs-major-version 23) (load ...) (let ... ...)) (let* (... ... ...
... ...) (add-to-list ... nxhtml-dir) (add-to-list ... related-dir)
(add-to-list ... util-dir) (add-to-list ... nxhtml-install-dir)
(add-to-list ... company-dir) (add-to-list ... tests-dir) (setq
web-autoload-default-filename-element nxhtml-install-dir) (message
"... nXhtml loading %.1f seconds elapsed ..." ...) (load ...) (message
"... nXhtml loading %.1f seconds elapsed ..." ...) (message "Turn on
`nxhtml-global-minor-mode' unconditionally") (nxhtml-global-minor-mode
1) (message "... nXhtml loading %.1f seconds elapsed ..." ...) (when
... ... ...) (message "... nXhtml loading %.1f seconds elapsed ..."
...) (load ...)) (message "... nXhtml loading %.1f seconds elapsed
..." (- ... nxhtml-load-time-start)) (when nxhtml-flymake-setup
(flymake-js-load) (flymake-css-load) (flymake-java-1-load) (add-hook
... ...)) (nxhtml-list-loaded-features nil) (message "Nxml/Nxhtml
Autostart.el loaded in %.1f seconds" (- ... nxhtml-load-time-start)))
  eval-buffer()  ; Reading at buffer position 8253
  call-interactively(eval-buffer nil nil)


There is obviously something I got wrong in the evaluation order since
now, in this situation, the macro now tries to evaluate

  (progn rngalt-display-validation-header
rngalt-display-validation-header-toggle)

I expected it to redefine the defcustom and the defun instead.
Can someone please try to explain what is going on?




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

* Re: Need some education on defmacro define-toggle
       [not found] ` <mailman.352.1262028532.18930.help-gnu-emacs@gnu.org>
@ 2009-12-28 21:33   ` Pascal J. Bourguignon
  2009-12-28 21:58     ` Lennart Borgman
       [not found]     ` <mailman.358.1262037566.18930.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 6+ messages in thread
From: Pascal J. Bourguignon @ 2009-12-28 21:33 UTC (permalink / raw)
  To: help-gnu-emacs

Lennart Borgman <lennart.borgman@gmail.com> writes:

> On Mon, Dec 28, 2009 at 6:16 AM, Lennart Borgman
> <lennart.borgman@gmail.com> wrote:
>> I just got into some trouble because of a badly written macro I
>> believe. After the long discussions about defmacro here I wonder if
>> anyone wants to help me out. How should I write the defmacro below?
>
>
> I resorted to self education (which is not too bad). However I still
> got problems - just on a more complicated level. The macro now looks
> like this:
>
> (defmacro define-toggle (symbol value doc &rest args)
>   "Declare SYMBOL as a customizable variable with a toggle function."
>   (declare   (doc-string 3)   (debug t))
>   (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
>          (SYMBOL-name (symbol-name symbol))
>          (var-doc doc)
>          (fun-doc (concat "Toggles the \(boolean) value of `" SYMBOL-name
>                           "'.\nFor how to set it permanently see this
> variable.\n")))
>     (let ((var (append `(defcustom ,symbol ,value ,var-doc)
>                 args
>                 nil))
>           (fun `(defun ,SYMBOL-toggle ()
>                    ,fun-doc
>                    (interactive)
>                    (customize-set-variable (quote ,symbol) (not ,symbol)))))
>       `(list 'progn ,var ,fun))))
>
> This seems to work, but if the call to define-toggle already has been
> done then loading a file with this define-toggle gives trouble:
>
> Debugger entered--Lisp error: (void-variable rngalt-display-validation-header-toggle)
>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>   (define-toggle rngalt-display-validation-header t "Display XML validation headers at the top of buffer when t.\nThe validation header is only displayed in buffers where the main\nmajor mode is derivd from `nxml-mode'." :set (lambda (sym val) (set-default sym val) (rngalt-update-validation-header-overlay-everywhere)) :group (quote relax-ng) :group (quote nxhtml))
>
> ...
>
> There is obviously something I got wrong in the evaluation order since
> now, in this situation, the macro now tries to evaluate
>
>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>
> I expected it to redefine the defcustom and the defun instead.
> Can someone please try to explain what is going on?

There must be an eval somewhere that tries to evaluate one time too many.


That said, why doesn't your macro just return 

   `(progn ,var ,fun)

instead of returning a list form that evaluates to something such as

   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)

that needs to be evaluated (and of course fails since you didn't
define these symbols as variables)?


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/


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

* Re: Need some education on defmacro define-toggle
  2009-12-28 21:33   ` Pascal J. Bourguignon
@ 2009-12-28 21:58     ` Lennart Borgman
       [not found]     ` <mailman.358.1262037566.18930.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 6+ messages in thread
From: Lennart Borgman @ 2009-12-28 21:58 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: help-gnu-emacs

On Mon, Dec 28, 2009 at 10:33 PM, Pascal J. Bourguignon
<pjb@informatimago.com> wrote:
> Lennart Borgman <lennart.borgman@gmail.com> writes:
>
>> On Mon, Dec 28, 2009 at 6:16 AM, Lennart Borgman
>> <lennart.borgman@gmail.com> wrote:
>>> I just got into some trouble because of a badly written macro I
>>> believe. After the long discussions about defmacro here I wonder if
>>> anyone wants to help me out. How should I write the defmacro below?
>>
>>
>> I resorted to self education (which is not too bad). However I still
>> got problems - just on a more complicated level. The macro now looks
>> like this:
>>
>> (defmacro define-toggle (symbol value doc &rest args)
>>   "Declare SYMBOL as a customizable variable with a toggle function."
>>   (declare   (doc-string 3)   (debug t))
>>   (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
>>          (SYMBOL-name (symbol-name symbol))
>>          (var-doc doc)
>>          (fun-doc (concat "Toggles the \(boolean) value of `" SYMBOL-name
>>                           "'.\nFor how to set it permanently see this
>> variable.\n")))
>>     (let ((var (append `(defcustom ,symbol ,value ,var-doc)
>>                 args
>>                 nil))
>>           (fun `(defun ,SYMBOL-toggle ()
>>                    ,fun-doc
>>                    (interactive)
>>                    (customize-set-variable (quote ,symbol) (not ,symbol)))))
>>       `(list 'progn ,var ,fun))))
>>
>> This seems to work, but if the call to define-toggle already has been
>> done then loading a file with this define-toggle gives trouble:
>>
>> Debugger entered--Lisp error: (void-variable rngalt-display-validation-header-toggle)
>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>   (define-toggle rngalt-display-validation-header t "Display XML validation headers at the top of buffer when t.\nThe validation header is only displayed in buffers where the main\nmajor mode is derivd from `nxml-mode'." :set (lambda (sym val) (set-default sym val) (rngalt-update-validation-header-overlay-everywhere)) :group (quote relax-ng) :group (quote nxhtml))
>>
>> ...
>>
>> There is obviously something I got wrong in the evaluation order since
>> now, in this situation, the macro now tries to evaluate
>>
>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>
>> I expected it to redefine the defcustom and the defun instead.
>> Can someone please try to explain what is going on?
>
> There must be an eval somewhere that tries to evaluate one time too many.


Hm, yes, but it is not mine...

As you can see from the backtrace there is some eval-buffer in the stack.



> That said, why doesn't your macro just return
>
>   `(progn ,var ,fun)
>
> instead of returning a list form that evaluates to something such as
>
>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>
> that needs to be evaluated (and of course fails since you didn't
> define these symbols as variables)?


It fails sometimes, but not always. It looks like it has something to
do with those eval above, but I do not understand how. If I just do
eval-buffer it works as I expect it to.

I have done some small changes and at the moment it seems to work, but
I have no idea why... There is clearly something in the order of
evaluation that beats me. If I just print out the values of fun and
var before comuting the result to return they look as I expect them
to, ie they are lists. But then in the progn list they are converted
to symbols, in some step.




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

* Re: Need some education on defmacro define-toggle
       [not found]     ` <mailman.358.1262037566.18930.help-gnu-emacs@gnu.org>
@ 2009-12-29  0:37       ` Pascal J. Bourguignon
  2009-12-29  0:49         ` Lennart Borgman
  0 siblings, 1 reply; 6+ messages in thread
From: Pascal J. Bourguignon @ 2009-12-29  0:37 UTC (permalink / raw)
  To: help-gnu-emacs

Lennart Borgman <lennart.borgman@gmail.com> writes:

> On Mon, Dec 28, 2009 at 10:33 PM, Pascal J. Bourguignon
> <pjb@informatimago.com> wrote:
>> Lennart Borgman <lennart.borgman@gmail.com> writes:
>>
>>> On Mon, Dec 28, 2009 at 6:16 AM, Lennart Borgman
>>> <lennart.borgman@gmail.com> wrote:
>>>> I just got into some trouble because of a badly written macro I
>>>> believe. After the long discussions about defmacro here I wonder if
>>>> anyone wants to help me out. How should I write the defmacro below?
>>>
>>>
>>> I resorted to self education (which is not too bad). However I still
>>> got problems - just on a more complicated level. The macro now looks
>>> like this:
>>>
>>> (defmacro define-toggle (symbol value doc &rest args)
>>>   "Declare SYMBOL as a customizable variable with a toggle function."
>>>   (declare   (doc-string 3)   (debug t))
>>>   (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
>>>          (SYMBOL-name (symbol-name symbol))
>>>          (var-doc doc)
>>>          (fun-doc (concat "Toggles the \(boolean) value of `" SYMBOL-name
>>>                           "'.\nFor how to set it permanently see this
>>> variable.\n")))
>>>     (let ((var (append `(defcustom ,symbol ,value ,var-doc)
>>>                 args
>>>                 nil))
>>>           (fun `(defun ,SYMBOL-toggle ()
>>>                    ,fun-doc
>>>                    (interactive)
>>>                    (customize-set-variable (quote ,symbol) (not ,symbol)))))
>>>       `(list 'progn ,var ,fun))))
>>>
>>> This seems to work, but if the call to define-toggle already has been
>>> done then loading a file with this define-toggle gives trouble:
>>>
>>> Debugger entered--Lisp error: (void-variable rngalt-display-validation-header-toggle)
>>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>>   (define-toggle rngalt-display-validation-header t "Display XML validation headers at the top of buffer when t.\nThe validation header is only displayed in buffers where the main\nmajor mode is derivd from `nxml-mode'." :set (lambda (sym val) (set-default sym val) (rngalt-update-validation-header-overlay-everywhere)) :group (quote relax-ng) :group (quote nxhtml))
>>>
>>> ...
>>>
>>> There is obviously something I got wrong in the evaluation order since
>>> now, in this situation, the macro now tries to evaluate
>>>
>>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>>
>>> I expected it to redefine the defcustom and the defun instead.
>>> Can someone please try to explain what is going on?
>>
>> There must be an eval somewhere that tries to evaluate one time too many.
>
>
> Hm, yes, but it is not mine...
>
> As you can see from the backtrace there is some eval-buffer in the stack.
>
>
>
>> That said, why doesn't your macro just return
>>
>>   `(progn ,var ,fun)
>>
>> instead of returning a list form that evaluates to something such as
>>
>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>
>> that needs to be evaluated (and of course fails since you didn't
>> define these symbols as variables)?
>
>
> It fails sometimes, but not always. It looks like it has something to
> do with those eval above, but I do not understand how. If I just do
> eval-buffer it works as I expect it to.
>
> I have done some small changes and at the moment it seems to work, but
> I have no idea why... There is clearly something in the order of
> evaluation that beats me. If I just print out the values of fun and
> var before comuting the result to return they look as I expect them
> to, ie they are lists. But then in the progn list they are converted
> to symbols, in some step.

Of course, when you evaluate `(list 'progn ,defcustom-form ,defun-form)
the defcustom and the defun are evaluated, and they return their name argument.

That's why I advise you to write instead:

     `(progn ,defcustom-form ,defun-form)


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/


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

* Re: Need some education on defmacro define-toggle
  2009-12-29  0:37       ` Pascal J. Bourguignon
@ 2009-12-29  0:49         ` Lennart Borgman
  0 siblings, 0 replies; 6+ messages in thread
From: Lennart Borgman @ 2009-12-29  0:49 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: help-gnu-emacs

On Tue, Dec 29, 2009 at 1:37 AM, Pascal J. Bourguignon
<pjb@informatimago.com> wrote:
> Lennart Borgman <lennart.borgman@gmail.com> writes:
>
>> On Mon, Dec 28, 2009 at 10:33 PM, Pascal J. Bourguignon
>> <pjb@informatimago.com> wrote:
>>> Lennart Borgman <lennart.borgman@gmail.com> writes:
>>>
>>>> On Mon, Dec 28, 2009 at 6:16 AM, Lennart Borgman
>>>> <lennart.borgman@gmail.com> wrote:
>>>>> I just got into some trouble because of a badly written macro I
>>>>> believe. After the long discussions about defmacro here I wonder if
>>>>> anyone wants to help me out. How should I write the defmacro below?
>>>>
>>>>
>>>> I resorted to self education (which is not too bad). However I still
>>>> got problems - just on a more complicated level. The macro now looks
>>>> like this:
>>>>
>>>> (defmacro define-toggle (symbol value doc &rest args)
>>>>   "Declare SYMBOL as a customizable variable with a toggle function."
>>>>   (declare   (doc-string 3)   (debug t))
>>>>   (let* ((SYMBOL-toggle (intern (concat (symbol-name symbol) "-toggle")))
>>>>          (SYMBOL-name (symbol-name symbol))
>>>>          (var-doc doc)
>>>>          (fun-doc (concat "Toggles the \(boolean) value of `" SYMBOL-name
>>>>                           "'.\nFor how to set it permanently see this
>>>> variable.\n")))
>>>>     (let ((var (append `(defcustom ,symbol ,value ,var-doc)
>>>>                 args
>>>>                 nil))
>>>>           (fun `(defun ,SYMBOL-toggle ()
>>>>                    ,fun-doc
>>>>                    (interactive)
>>>>                    (customize-set-variable (quote ,symbol) (not ,symbol)))))
>>>>       `(list 'progn ,var ,fun))))
>>
>>
>>> That said, why doesn't your macro just return
>>>
>>>   `(progn ,var ,fun)
>>>
>>> instead of returning a list form that evaluates to something such as
>>>
>>>   (progn rngalt-display-validation-header rngalt-display-validation-header-toggle)
>>>
>>> that needs to be evaluated (and of course fails since you didn't
>>> define these symbols as variables)?
>>
>>
>> It fails sometimes, but not always. It looks like it has something to
>> do with those eval above, but I do not understand how. If I just do
>> eval-buffer it works as I expect it to.
>
> Of course, when you evaluate `(list 'progn ,defcustom-form ,defun-form)
> the defcustom and the defun are evaluated, and they return their name argument.


Hm, in that case the defcustom and defun must have been evaluated
earlier because they did exist. Now I have changed this so many times
so I am not sure when.


> That's why I advise you to write instead:
>
>     `(progn ,defcustom-form ,defun-form)


Thanks, yes, I understand that. I tried a lot of alternatives though
to get evaluation at the right time. Surprisingly enough it sometimes
worked with `(list 'prog ,var ,fun) and sometimes not.

I did not dig deep in this, because I know there are other people here
who understands this much better than me ... ;-)

In the current implementation (which seems to work) I have this

    (let ((var (append `(defcustom ,symbol ,value ,var-doc)
                args
                nil))
          (fun `(defun ,SYMBOL-toggle ()
                  ,fun-doc
                  (interactive)
                  (customize-set-variable (quote ,symbol) (not ,symbol)))))
      `(progn ,fun ,var)
    )))

Does that look correct?




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

end of thread, other threads:[~2009-12-29  0:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-28  5:16 Need some education on defmacro define-toggle Lennart Borgman
2009-12-28 19:28 ` Lennart Borgman
     [not found] ` <mailman.352.1262028532.18930.help-gnu-emacs@gnu.org>
2009-12-28 21:33   ` Pascal J. Bourguignon
2009-12-28 21:58     ` Lennart Borgman
     [not found]     ` <mailman.358.1262037566.18930.help-gnu-emacs@gnu.org>
2009-12-29  0:37       ` Pascal J. Bourguignon
2009-12-29  0:49         ` Lennart Borgman

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.