all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Evaluation of macro arguments
@ 2016-01-05 10:59 Marcin Borkowski
  2016-01-05 12:55 ` Stefan Monnier
  2016-01-05 19:22 ` Pascal J. Bourguignon
  0 siblings, 2 replies; 10+ messages in thread
From: Marcin Borkowski @ 2016-01-05 10:59 UTC (permalink / raw)
  To: Help Gnu Emacs mailing list

Hi all,

continuing my quest to grok macro argument evaluation issues, I'd like
(again) to make sure that I get it correctly.  So I have this simple
macro generating a list of consecutive numbers (which is not without
problems - I am aware of those, namely (i) it uses hard-coded symbols
instead of generating them on the fly, and (ii) it has no error
checking):

(defmacro range (from dir to)
  `(let ((delta (cond ((eq ',dir 'upto) 1)
                      ((eq ',dir 'downto) -1)))
         (i ,from)
         (list nil))
     (while (not (= i ,to))
       (push i list)
       (setq i (+ i delta)))
     (nreverse list)))

Do I get it correctly that if I want to write an Edebug spec for this
macro, I should mark the second argument as _not evaluated_, because its
value is actually quoted?

(Also, do I get it right that the spec for the second argument should be
e.g. `symbolp', or - if I want to have more error-checking while
edebugging - I should _define_ a predicate like this

(defun upto-or-downto-p (symbol)
  (memq symbol '(upto downto)))

since the predicate in the edebug spec cannot be a lambda expression?

TIA,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



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

* Re: Evaluation of macro arguments
  2016-01-05 10:59 Evaluation of macro arguments Marcin Borkowski
@ 2016-01-05 12:55 ` Stefan Monnier
  2016-01-13 22:16   ` Marcin Borkowski
  2016-01-05 19:22 ` Pascal J. Bourguignon
  1 sibling, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2016-01-05 12:55 UTC (permalink / raw)
  To: help-gnu-emacs

> Do I get it correctly that if I want to write an Edebug spec for this
> macro, I should mark the second argument as _not evaluated_, because its
> value is actually quoted?

That's right.

> (Also, do I get it right that the spec for the second argument should be
> e.g. `symbolp', or - if I want to have more error-checking while
> edebugging - I should _define_ a predicate like this
>
> (defun upto-or-downto-p (symbol)
>   (memq symbol '(upto downto)))
>
> since the predicate in the edebug spec cannot be a lambda expression?

Something like it, yes (tho it's not really "checked while edebugging".
Instead, such a precise Edebug spec would cause an error (and not
a very pretty one) when you ask Edebug to annotate the code).
I'd use a spec like (declare (debug (form symbolp form))).


        Stefan




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

* Re: Evaluation of macro arguments
  2016-01-05 10:59 Evaluation of macro arguments Marcin Borkowski
  2016-01-05 12:55 ` Stefan Monnier
@ 2016-01-05 19:22 ` Pascal J. Bourguignon
  2016-01-05 19:39   ` Marcin Borkowski
  1 sibling, 1 reply; 10+ messages in thread
From: Pascal J. Bourguignon @ 2016-01-05 19:22 UTC (permalink / raw)
  To: help-gnu-emacs

Marcin Borkowski <mbork@mbork.pl> writes:

> Hi all,
>
> continuing my quest to grok macro argument evaluation issues, I'd like
> (again) to make sure that I get it correctly.  So I have this simple
> macro generating a list of consecutive numbers (which is not without
> problems - I am aware of those, namely (i) it uses hard-coded symbols
> instead of generating them on the fly, and (ii) it has no error
> checking):
>
> (defmacro range (from dir to)
>   `(let ((delta (cond ((eq ',dir 'upto) 1)
>                       ((eq ',dir 'downto) -1)))
>          (i ,from)
>          (list nil))
>      (while (not (= i ,to))
>        (push i list)
>        (setq i (+ i delta)))
>      (nreverse list)))

(let ((i 0))
   (list (range  i 'upto (incf i 10))  ; bam!
         i))

I hope you may debug it well.


-- 
__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] 10+ messages in thread

* Re: Evaluation of macro arguments
  2016-01-05 19:22 ` Pascal J. Bourguignon
@ 2016-01-05 19:39   ` Marcin Borkowski
  2016-01-05 20:30     ` Marcin Borkowski
       [not found]     ` <mailman.1794.1452025850.843.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 10+ messages in thread
From: Marcin Borkowski @ 2016-01-05 19:39 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: help-gnu-emacs



On 2016-01-05, at 20:22, Pascal J. Bourguignon <pjb@informatimago.com> wrote:

> Marcin Borkowski <mbork@mbork.pl> writes:
>
>> Hi all,
>>
>> continuing my quest to grok macro argument evaluation issues, I'd like
>> (again) to make sure that I get it correctly.  So I have this simple
>> macro generating a list of consecutive numbers (which is not without
>> problems - I am aware of those, namely (i) it uses hard-coded symbols
>> instead of generating them on the fly, and (ii) it has no error
>> checking):
>>
>> (defmacro range (from dir to)
>>   `(let ((delta (cond ((eq ',dir 'upto) 1)
>>                       ((eq ',dir 'downto) -1)))
>>          (i ,from)
>>          (list nil))
>>      (while (not (= i ,to))
>>        (push i list)
>>        (setq i (+ i delta)))
>>      (nreverse list)))
>
> (let ((i 0))
>    (list (range  i 'upto (incf i 10))  ; bam!
>          i))
>
> I hope you may debug it well.

That's unfair, Pascal; I wrote that I'm aware of this, I know how to
make it work, and wasn't asking about it.

Best,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



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

* Re: Evaluation of macro arguments
  2016-01-05 19:39   ` Marcin Borkowski
@ 2016-01-05 20:30     ` Marcin Borkowski
       [not found]     ` <mailman.1794.1452025850.843.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 10+ messages in thread
From: Marcin Borkowski @ 2016-01-05 20:30 UTC (permalink / raw)
  To: Pascal J. Bourguignon; +Cc: help-gnu-emacs



On 2016-01-05, at 20:39, Marcin Borkowski <mbork@mbork.pl> wrote:

> On 2016-01-05, at 20:22, Pascal J. Bourguignon <pjb@informatimago.com> wrote:
>
>> Marcin Borkowski <mbork@mbork.pl> writes:
>>
>>> Hi all,
>>>
>>> continuing my quest to grok macro argument evaluation issues, I'd like
>>> (again) to make sure that I get it correctly.  So I have this simple
>>> macro generating a list of consecutive numbers (which is not without
>>> problems - I am aware of those, namely (i) it uses hard-coded symbols
>>> instead of generating them on the fly, and (ii) it has no error
>>> checking):
>>>
>>> (defmacro range (from dir to)
>>>   `(let ((delta (cond ((eq ',dir 'upto) 1)
>>>                       ((eq ',dir 'downto) -1)))
>>>          (i ,from)
>>>          (list nil))
>>>      (while (not (= i ,to))
>>>        (push i list)
>>>        (setq i (+ i delta)))
>>>      (nreverse list)))
>>
>> (let ((i 0))
>>    (list (range  i 'upto (incf i 10))  ; bam!
>>          i))
>>
>> I hope you may debug it well.
>
> That's unfair, Pascal; I wrote that I'm aware of this, I know how to
> make it work, and wasn't asking about it.

OK, technically you win, since I didn't notice that I evaluated `to'
multiple times.  Still, this was not what I was asking about - though
thank you for pointing that out to me.  It would be rather embarassing
if I missed it.

Best,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



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

* Re: Evaluation of macro arguments
       [not found]     ` <mailman.1794.1452025850.843.help-gnu-emacs@gnu.org>
@ 2016-01-08 23:13       ` duthen.mac.01
  0 siblings, 0 replies; 10+ messages in thread
From: duthen.mac.01 @ 2016-01-08 23:13 UTC (permalink / raw)
  To: help-gnu-emacs

Hello!

Le mardi 5 janvier 2016 21:30:52 UTC+1, Marcin Borkowski a écrit :
> On 2016-01-05, at 20:39, Marcin Borkowski  wrote:
> 
> > On 2016-01-05, at 20:22, Pascal J. Bourguignon wrote:
> >>
> >> (let ((i 0))
> >>    (list (range  i 'upto (incf i 10))  ; bam!
> >>          i))
> >>
> >> I hope you may debug it well.

> OK, technically you win, since I didn't notice that I evaluated `to'
> multiple times.  Still, this was not what I was asking about - though
> thank you for pointing that out to me.  It would be rather embarassing
> if I missed it.

If you plan to use a variable "dir" with a "dynamic" value like this, 
   (range a (if some-test 'upto 'downto) b)
you have to "evaluate" "dir" at run time.

But if you want to restrict it to a "lexical" symbol, you can do something like this:

(defmacro range (from dir to)
  (declare (debug (form symbolp form)) (indent 3))
  (let ((delta
         (cond
          ((eq dir 'upto) 1)
          ((eq dir 'downto) -1)
          (t (error "wrong dir: %s" dir)))))
    `(let ((i ,from)
           (to ,to)
           (list (list)))
       (while (not (= i to))
         (push i list)
         (setq i (+ i ,delta)))
       (nreverse list))))

(defun test ()
  (let ((i 0))
    (list (range i upto (incf i 10))
          i)))

(test) -> ((0 1 2 3 4 5 6 7 8 9) 10)

Note that "dir" is checked at expansion time and may generate an error.


I have just a couple of remarks concerning macros:

* if some variable is to be used more than once inside the body macro, it should be better to link it to a local variable (like "to" and "from" here), as already seen.

* if the body of the macro does not embed any user code, you don't need to be afraid of variable conflict. You don't need to generate local variables.

* you must respect the order of argument "evaluation".
For example, this couple of macros seem ok, but...

(defmacro range-up (from to)
  (declare (debug (form form)) (indent 2))
  `(let ((i ,from)
         (to ,to)
         (list (list)))
     (while (not (> i to))
       (push i list)
       (incf i))
     (nreverse list)))

(defmacro range-down (from to)
  (declare (debug (form form)) (indent 2))
  `(nreverse (range-up ,to ,from)))

ELISP> (range-up 3 7)
(3 4 5 6 7)

ELISP> (range-down 7 3)
(7 6 5 4 3)

ELISP> (let ((i 7)) (range-down i (decf i 4)))
(3)

HTH
jack


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

* Re: Evaluation of macro arguments
  2016-01-05 12:55 ` Stefan Monnier
@ 2016-01-13 22:16   ` Marcin Borkowski
  2016-01-14 13:47     ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Marcin Borkowski @ 2016-01-13 22:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs


On 2016-01-05, at 13:55, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

>> Do I get it correctly that if I want to write an Edebug spec for this
>> macro, I should mark the second argument as _not evaluated_, because its
>> value is actually quoted?
>
> That's right.
>
>> (Also, do I get it right that the spec for the second argument should be
>> e.g. `symbolp', or - if I want to have more error-checking while
>> edebugging - I should _define_ a predicate like this
>>
>> (defun upto-or-downto-p (symbol)
>>   (memq symbol '(upto downto)))
>>
>> since the predicate in the edebug spec cannot be a lambda expression?
>
> Something like it, yes (tho it's not really "checked while edebugging".

Hi,

I finally sat down to this.

I still don't get it.  If it's not checked while edebugging, what's the
point of the precise declaration?

> Instead, such a precise Edebug spec would cause an error (and not
> a very pretty one) when you ask Edebug to annotate the code).
> I'd use a spec like (declare (debug (form symbolp form))).

I tried it and did not get any error message.  Why?  More precisely,
here's what I have done:

--8<---------------cut here---------------start------------->8---
(defun upto-or-downto-p (symbol)
  (memq symbol '(upto downto)))

(defmacro range (from dir to)
  "Return a list of numbers starting with FROM and going up to
TO-1 if DIR is the symbol 'upto or down to TO+1 if DIR is the
symbol 'downto.  Warning: this version is broken!"
  (declare (debug (form upto-or-downto-p form)))
  `(let ((delta (cond ((eq ',dir 'upto) 1)
		      ((eq ',dir 'downto) -1)))
         (i ,from)
         (list nil))
     (while (not (= i ,to))
       (push i list)
       (setq i (+ i delta)))
     (nreverse list)))

(range (- 5 4) upto (+ 4 6))
--8<---------------cut here---------------end--------------->8---

Then I pressed C-u C-M-x on the last form, and everything went
smoothly.  If I replace 'upto with something else, I get this:

edebug-syntax-error: Invalid read syntax: upto-or-downto-p, "failed"

So basically it seems that I was (more or less) right.  OTOH, I can't
be right about anything Emacs-related and you be wrong on it, so what's
going on?

>         Stefan

Best,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



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

* Re: Evaluation of macro arguments
  2016-01-13 22:16   ` Marcin Borkowski
@ 2016-01-14 13:47     ` Stefan Monnier
  2016-01-14 20:32       ` Marcin Borkowski
  0 siblings, 1 reply; 10+ messages in thread
From: Stefan Monnier @ 2016-01-14 13:47 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs

> I still don't get it.  If it's not checked while edebugging, what's the
> point of the precise declaration?

It's *used* (rather than checked) when *setting up* the Edebug
instrumentation, rather than while single stepping through the code.
[ I realize now that maybe "setup edebug instrumentation" is what you
  meant by "edebugging", while to me "edebugging" means something more
  like single-stepping, which is what happens after the instrumentation
  has been put in place.  ]

>> Instead, such a precise Edebug spec would cause an error (and not
>> a very pretty one) when you ask Edebug to annotate the code).
>> I'd use a spec like (declare (debug (form symbolp form))).
> I tried it and did not get any error message.  Why?  More precisely,
> here's what I have done:

> --8<---------------cut here---------------start------------->8---
> (defun upto-or-downto-p (symbol)
>   (memq symbol '(upto downto)))

> (defmacro range (from dir to)
>   "Return a list of numbers starting with FROM and going up to
> TO-1 if DIR is the symbol 'upto or down to TO+1 if DIR is the
> symbol 'downto.  Warning: this version is broken!"
>   (declare (debug (form upto-or-downto-p form)))
>   `(let ((delta (cond ((eq ',dir 'upto) 1)
> 		      ((eq ',dir 'downto) -1)))
>          (i ,from)
>          (list nil))
>      (while (not (= i ,to))
>        (push i list)
>        (setq i (+ i delta)))
>      (nreverse list)))

> (range (- 5 4) upto (+ 4 6))
> --8<---------------cut here---------------end--------------->8---

> Then I pressed C-u C-M-x on the last form, and everything went
> smoothly.

Yes, that's normal.

> If I replace 'upto with something else, I get this:
> edebug-syntax-error: Invalid read syntax: upto-or-downto-p, "failed"

That's the error I was referring to (and indeed, if the code is right
you should not be getting an error).  The error can become more
troublesome for more complex Edebug specs where Edebug can try various
alternatives in which case the error you get may be about an alternative
which shouldn't have been tried anyway.

To see the difference between "instrumentation" and "single-stepping",
you need to try C-u C-M-x on something like

  (defun my-foo () (range (- 5 4) typo (+ 4 6)))

where you'll immediately get the error during C-u C-M-x rather than latr
on when you call my-foo.

> So basically it seems that I was (more or less) right.  OTOH, I can't
> be right about anything Emacs-related and you be wrong on it, so what's
> going on?

I think we were just in violent agreement.


        Stefan



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

* Re: Evaluation of macro arguments
  2016-01-14 13:47     ` Stefan Monnier
@ 2016-01-14 20:32       ` Marcin Borkowski
  2016-01-14 23:05         ` Stefan Monnier
  0 siblings, 1 reply; 10+ messages in thread
From: Marcin Borkowski @ 2016-01-14 20:32 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs


On 2016-01-14, at 14:47, Stefan Monnier <monnier@iro.umontreal.ca> wrote:

>> I still don't get it.  If it's not checked while edebugging, what's the
>> point of the precise declaration?
>
> It's *used* (rather than checked) when *setting up* the Edebug
> instrumentation, rather than while single stepping through the code.
> [ I realize now that maybe "setup edebug instrumentation" is what you
>   meant by "edebugging", while to me "edebugging" means something more
>   like single-stepping, which is what happens after the instrumentation
>   has been put in place.  ]

Well, it turns out that I was quite confused.  Now that you wrote it, it
does make perfect sense; in my experiments with this issue
I instrumented single forms to be evaluated and not defuns, so (as you
wrote below) there was no observable difference (both steps happened
basically instantaneously).

>>> Instead, such a precise Edebug spec would cause an error (and not
>>> a very pretty one) when you ask Edebug to annotate the code).
>>> I'd use a spec like (declare (debug (form symbolp form))).
>> I tried it and did not get any error message.  Why?  More precisely,
>> here's what I have done:
>
>> --8<---------------cut here---------------start------------->8---
>> (defun upto-or-downto-p (symbol)
>>   (memq symbol '(upto downto)))
>
>> (defmacro range (from dir to)
>>   "Return a list of numbers starting with FROM and going up to
>> TO-1 if DIR is the symbol 'upto or down to TO+1 if DIR is the
>> symbol 'downto.  Warning: this version is broken!"
>>   (declare (debug (form upto-or-downto-p form)))
>>   `(let ((delta (cond ((eq ',dir 'upto) 1)
>> 		      ((eq ',dir 'downto) -1)))
>>          (i ,from)
>>          (list nil))
>>      (while (not (= i ,to))
>>        (push i list)
>>        (setq i (+ i delta)))
>>      (nreverse list)))
>
>> (range (- 5 4) upto (+ 4 6))
>> --8<---------------cut here---------------end--------------->8---
>
>> Then I pressed C-u C-M-x on the last form, and everything went
>> smoothly.
>
> Yes, that's normal.

I would hope so! ;-)

>> If I replace 'upto with something else, I get this:
>> edebug-syntax-error: Invalid read syntax: upto-or-downto-p, "failed"
>
> That's the error I was referring to (and indeed, if the code is right
> you should not be getting an error).  The error can become more
> troublesome for more complex Edebug specs where Edebug can try various
> alternatives in which case the error you get may be about an alternative
> which shouldn't have been tried anyway.

Ah, so it has something to do with those &or, &and etc.?  I have to
admit that I did not really understand that part of the manual.  I will
try to understand it some day (sooner than later, I hope).  It would be
great if I managed to come up with a patch for the manual then to make
it easier for future generations. ;-)

Are there any worthy examples of edebug specs in Emacs sources?  (I
could just grep for them - and I'll probably do that anyway - but if
somebody could point me to some of those which are especially suitable
for understanding the thing, it would be great.  Of course, I will start
with the examples provided in the manual.)

> To see the difference between "instrumentation" and "single-stepping",
> you need to try C-u C-M-x on something like
>
>   (defun my-foo () (range (- 5 4) typo (+ 4 6)))
>
> where you'll immediately get the error during C-u C-M-x rather than latr
> on when you call my-foo.

Makes sense, especially that (in my macro) the upto/downto has to sit
right there in the code (I mean, literally - it cannot be the result of
any evaluation, since that argument of my macro is never evaluated!)

>> So basically it seems that I was (more or less) right.  OTOH, I can't
>> be right about anything Emacs-related and you be wrong on it, so what's
>> going on?
>
> I think we were just in violent agreement.

;-)

>         Stefan

Thanks for your patience!  I'm slowly learning this stuff, and I hope to
"pay back" to the community by at least writing a blog post, and maybe
a patch for the manual.

Best,

-- 
Marcin Borkowski
http://octd.wmi.amu.edu.pl/en/Marcin_Borkowski
Faculty of Mathematics and Computer Science
Adam Mickiewicz University



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

* Re: Evaluation of macro arguments
  2016-01-14 20:32       ` Marcin Borkowski
@ 2016-01-14 23:05         ` Stefan Monnier
  0 siblings, 0 replies; 10+ messages in thread
From: Stefan Monnier @ 2016-01-14 23:05 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs

> Ah, so it has something to do with those &or, &and etc.?

Right.

> Are there any worthy examples of edebug specs in Emacs sources?

As a general rule of thumb, the more complex the macro, the more complex
the debug spec.  So you can take a look at the specs for cl-loop or
pcase if you want "interesting" examples.


        Stefan



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

end of thread, other threads:[~2016-01-14 23:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-05 10:59 Evaluation of macro arguments Marcin Borkowski
2016-01-05 12:55 ` Stefan Monnier
2016-01-13 22:16   ` Marcin Borkowski
2016-01-14 13:47     ` Stefan Monnier
2016-01-14 20:32       ` Marcin Borkowski
2016-01-14 23:05         ` Stefan Monnier
2016-01-05 19:22 ` Pascal J. Bourguignon
2016-01-05 19:39   ` Marcin Borkowski
2016-01-05 20:30     ` Marcin Borkowski
     [not found]     ` <mailman.1794.1452025850.843.help-gnu-emacs@gnu.org>
2016-01-08 23:13       ` duthen.mac.01

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.