all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Concern around use of eval
@ 2015-03-19  6:53 Les Harris
  2015-03-19  8:00 ` Tassilo Horn
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Les Harris @ 2015-03-19  6:53 UTC (permalink / raw)
  To: help-gnu-emacs

I have a situation where I want to generate a bunch of nearly identical
predicate functions. Previously I had just manually defined these things
one by one but was never happy with such an obvious inefficiency (or
maintaining it). Tonight I decided I'd fix this and whacked them and
implemented a way of doing it where I can iterate over a list containing
labels and define these predicate functions using those labels:

,----
| (defvar lh/labels '("label1" "label2" "label3"))
| 
| (defmacro lh/gen-predicate (label)
|   `(defun ,(intern (concat "lh/" label "-p")) ()
|             (member ,label *lh/system-label-store*)))
| 
| (defun lh/define-predicates ()
|   (dolist (label lh/labels)
|     (eval `(lh/gen-predicate ,label))))
| (lh/define-predicates)
`----

Now this all works fine and I get my auto-generated predicates, so
success. My question/concern/niggle is around the use of (eval) in
lh/define-predicates. If I don't put eval in there then the defun the
macro evaluates into never gets evaluated itself. Stylistically, is
there a better way to do this or am I just being weird about (eval) and
should just get over it?

-- 
Do they only stand
By ignorance, is that their happy state,
The proof of their obedience and their faith?




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

* Re: Concern around use of eval
  2015-03-19  6:53 Concern around use of eval Les Harris
@ 2015-03-19  8:00 ` Tassilo Horn
       [not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
  2015-03-19 14:07 ` Stefan Monnier
  2 siblings, 0 replies; 17+ messages in thread
From: Tassilo Horn @ 2015-03-19  8:00 UTC (permalink / raw)
  To: Les Harris; +Cc: help-gnu-emacs

Les Harris <les@lesharris.com> writes:

Hi Les,

> ,----
> | (defvar lh/labels '("label1" "label2" "label3"))
> | 
> | (defmacro lh/gen-predicate (label)
> |   `(defun ,(intern (concat "lh/" label "-p")) ()
> |             (member ,label *lh/system-label-store*)))
> | 
> | (defun lh/define-predicates ()
> |   (dolist (label lh/labels)
> |     (eval `(lh/gen-predicate ,label))))
> | (lh/define-predicates)
> `----
>
> Now this all works fine and I get my auto-generated predicates, so
> success. My question/concern/niggle is around the use of (eval) in
> lh/define-predicates. If I don't put eval in there then the defun the
> macro evaluates into never gets evaluated itself. Stylistically, is
> there a better way to do this or am I just being weird about (eval) and
> should just get over it?

Well, in case the `lh/label' value is available at compile-time then
`lh/define-predicates' can also be a macro and you can go like this:

--8<---------------cut here---------------start------------->8---
(defvar lh/labels '("label1" "label2" "label3"))

(defmacro lh/gen-predicate (label)
  `(defun ,(intern (concat "lh/" label "-p")) ()
     (member ,label *lh/system-label-store*)))

(defmacro lh/define-predicates ()
  `(progn
     ,@(mapcar (lambda (label)
		 `(lh/gen-predicate ,label))
	       lh/labels)))

(lh/define-predicates)
--8<---------------cut here---------------end--------------->8---

But if you know your labels only at runtime, then I think there's no way
around using `eval'.

Bye,
Tassilo



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

* Re: Concern around use of eval
       [not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
@ 2015-03-19  8:12   ` Joost Kremers
  2015-03-19  8:31     ` Tassilo Horn
       [not found]     ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
  0 siblings, 2 replies; 17+ messages in thread
From: Joost Kremers @ 2015-03-19  8:12 UTC (permalink / raw)
  To: help-gnu-emacs

Tassilo Horn wrote:
> Well, in case the `lh/label' value is available at compile-time then
> `lh/define-predicates' can also be a macro and you can go like this:
>
> --8<---------------cut here---------------start------------->8---
> (defvar lh/labels '("label1" "label2" "label3"))
>
> (defmacro lh/gen-predicate (label)
>   `(defun ,(intern (concat "lh/" label "-p")) ()
>      (member ,label *lh/system-label-store*)))
>
> (defmacro lh/define-predicates ()
>   `(progn
>      ,@(mapcar (lambda (label)
> 		 `(lh/gen-predicate ,label))
> 	       lh/labels)))
>
> (lh/define-predicates)
> --8<---------------cut here---------------end--------------->8---

Why not do it at the top level directly? E.g.:

,----
| (defvar lh/labels '("label1" "label2" "label3"))
| 
| (defmacro lh/gen-predicate (label)
|   `(defun ,(intern (concat "lh/" label "-p")) ()
|      (member ,label *lh/system-label-store*)))
| 
| (mapc (lambda (label)
|         (lh/gen-predicate label))
|       lh/labels)
`----


-- 
Joost Kremers                                   joostkremers@fastmail.fm
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)


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

* Re: Concern around use of eval
  2015-03-19  8:12   ` Joost Kremers
@ 2015-03-19  8:31     ` Tassilo Horn
       [not found]     ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
  1 sibling, 0 replies; 17+ messages in thread
From: Tassilo Horn @ 2015-03-19  8:31 UTC (permalink / raw)
  To: help-gnu-emacs

Joost Kremers <joost.m.kremers@gmail.com> writes:

> Why not do it at the top level directly? E.g.:
>
> ,----
> | (defvar lh/labels '("label1" "label2" "label3"))
> | 
> | (defmacro lh/gen-predicate (label)
> |   `(defun ,(intern (concat "lh/" label "-p")) ()
> |      (member ,label *lh/system-label-store*)))
> | 
> | (mapc (lambda (label)
> |         (lh/gen-predicate label))
> |       lh/labels)
> `----

That won't work because.  When reading the mapc form, emacs sees that
`lh/gen-predicate' is a macro and tries to expand it with the symbol
label as argument.  The macroexpansion takes place before the actual
execution of the code.

Bye,
Tassilo



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

* Re: Concern around use of eval
  2015-03-19  6:53 Concern around use of eval Les Harris
  2015-03-19  8:00 ` Tassilo Horn
       [not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
@ 2015-03-19 14:07 ` Stefan Monnier
  2015-03-20 15:17   ` Thierry Volpiatto
  2 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2015-03-19 14:07 UTC (permalink / raw)
  To: help-gnu-emacs

> | (defvar lh/labels '("label1" "label2" "label3"))
> | 
> | (defmacro lh/gen-predicate (label)
> |   `(defun ,(intern (concat "lh/" label "-p")) ()
> |             (member ,label *lh/system-label-store*)))
> | 
> | (defun lh/define-predicates ()
> |   (dolist (label lh/labels)
> |     (eval `(lh/gen-predicate ,label))))
> | (lh/define-predicates)

    ; -*- lexical-binding:t -*-

    (defvar lh/labels '("label1" "label2" "label3"))
    
    (defun lh/gen-predicate (label)
      (defalias (intern (concat "lh/" label "-p"))
        (lambda () (member label *lh/system-label-store*))))
    
    (defun lh/define-predicates ()
      (mapc #'lh/gen-predicate lh/labels))

    (lh/define-predicates)

> Stylistically, is there a better way to do this or am I just being
> weird about (eval) and should just get over it?

You're not weird about `eval'.  It's kind of like self-modifying code:
there are cases where you *really* need it, but they're extremely rare
and every time you use it when it's not *really* indispensable,
kittens die.


        Stefan




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

* Re: Concern around use of eval
  2015-03-19 14:07 ` Stefan Monnier
@ 2015-03-20 15:17   ` Thierry Volpiatto
  2015-03-20 17:19     ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
  0 siblings, 1 reply; 17+ messages in thread
From: Thierry Volpiatto @ 2015-03-20 15:17 UTC (permalink / raw)
  To: help-gnu-emacs

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>     (defun lh/gen-predicate (label)
>       (defalias (intern (concat "lh/" label "-p"))
                   ^^^^^^
In this case intern should not be highlighted, isn't it ?.

-- 
Thierry
Get my Gnupg key:
gpg --keyserver pgp.mit.edu --recv-keys 59F29997 




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

* Bug in Elisp font-locking (was: Concern around use of eval)
  2015-03-20 15:17   ` Thierry Volpiatto
@ 2015-03-20 17:19     ` Tassilo Horn
  2015-03-20 17:31       ` Bug in Elisp font-locking Stefan Monnier
  0 siblings, 1 reply; 17+ messages in thread
From: Tassilo Horn @ 2015-03-20 17:19 UTC (permalink / raw)
  To: Thierry Volpiatto; +Cc: help-gnu-emacs, emacs-devel

Thierry Volpiatto <thierry.volpiatto@gmail.com> writes:

>>     (defun lh/gen-predicate (label)
>>       (defalias (intern (concat "lh/" label "-p"))
>                   ^^^^^^
> In this case intern should not be highlighted, isn't it ?.

Indeed, it shouldn't be.  But the font-lock entry for definitions which
applies the function name face here matches next to `defun', `defmacro',
or `defalias' also `cl-defstruct', and that may have the two forms

  (defstruct struct-name ...)
  (defstruct (struct-name OPTIONS) ...)

and therefore, the regexp simply skips the paren.  The following patch
should fix that.

Cc-ing emacs-devel to ask if that's ok to commit.  Is it?  Or too much
hassle for just `defalias'?  (I think that's the only definition form
which is implemented as a function where the name may be provided by a
funcall.)

--8<---------------cut here---------------start------------->8---
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index 6b30773..614fbc6 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -320,14 +320,18 @@
     `( ;; Definitions.
       (,(concat "(" el-defs-re "\\_>"
                 ;; Any whitespace and defined object.
-                "[ \t'\(]*"
-                "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+                "[ \t']*"
+               ;; With defstruct, the name may follow a paren,
+               ;; e.g. (defstruct (foo-struct opts)...).
+                "\\(([ \t']*\\)?\\(\\(?:\\sw\\|\\s_\\)+\\)?")
        (1 font-lock-keyword-face)
-       (2 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type)))
-            (cond ((eq type 'var) font-lock-variable-name-face)
-                  ((eq type 'type) font-lock-type-face)
-                  (t font-lock-function-name-face)))
-          nil t))
+       (3 (let ((type (get (intern-soft (match-string 1)) 'lisp-define-type)))
+           (cond ((eq type 'var) font-lock-variable-name-face)
+                 ((eq type 'type) font-lock-type-face)
+                 ;; If match-string 2 is non-nil, we encountered a
+                 ;; form like (defalias (intern (concat s "-p"))).
+                 ((not (match-string 2)) font-lock-function-name-face)))
+         nil t))
       ;; Emacs Lisp autoload cookies.  Supports the slightly different
       ;; forms used by mh-e, calendar, etc.
       ("^;;;###\\([-a-z]*autoload\\)" 1 font-lock-warning-face prepend))
--8<---------------cut here---------------end--------------->8---

Bye,
Tassilo



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

* Re: Bug in Elisp font-locking
  2015-03-20 17:19     ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
@ 2015-03-20 17:31       ` Stefan Monnier
  2015-03-20 17:43         ` Drew Adams
  2015-03-20 18:47         ` Tassilo Horn
  0 siblings, 2 replies; 17+ messages in thread
From: Stefan Monnier @ 2015-03-20 17:31 UTC (permalink / raw)
  To: emacs-devel; +Cc: help-gnu-emacs

> Thierry Volpiatto <thierry.volpiatto@gmail.com> writes:
>>> (defun lh/gen-predicate (label)
>>> (defalias (intern (concat "lh/" label "-p"))
>> ^^^^^^
>> In this case intern should not be highlighted, isn't it ?.

Indeed.

>   (defstruct struct-name ...)
>   (defstruct (struct-name OPTIONS) ...)

Also for defun in Common-Lisp, there's (defun (setf foo) ...) where the
"setf" probably shouldn't be highlighted but the "foo" should.

> Cc-ing emacs-devel to ask if that's ok to commit.

Could explain what the patch does?


        Stefan




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

* RE: Bug in Elisp font-locking
  2015-03-20 17:31       ` Bug in Elisp font-locking Stefan Monnier
@ 2015-03-20 17:43         ` Drew Adams
  2015-03-20 18:47         ` Tassilo Horn
  1 sibling, 0 replies; 17+ messages in thread
From: Drew Adams @ 2015-03-20 17:43 UTC (permalink / raw)
  To: Stefan Monnier, emacs-devel; +Cc: help-gnu-emacs

How about dropping emacs-devel or help-gnu-emacs as recipient?
There should be no need to spread this over multiple lists, at
least at this point.  Please just move it to whichever you think
is most appropriate.

And if this is indeed about a bug, as the subject line says,
how about dropping them both and moving this to the bug tracker?



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

* Re: Bug in Elisp font-locking
  2015-03-20 17:31       ` Bug in Elisp font-locking Stefan Monnier
  2015-03-20 17:43         ` Drew Adams
@ 2015-03-20 18:47         ` Tassilo Horn
  2015-03-20 20:38           ` Stefan Monnier
  1 sibling, 1 reply; 17+ messages in thread
From: Tassilo Horn @ 2015-03-20 18:47 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs, emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>>>> (defun lh/gen-predicate (label)
>>>> (defalias (intern (concat "lh/" label "-p"))
>>>             ^^^^^^
>>> In this case intern should not be highlighted, isn't it ?.
>
> Indeed.
>
>>   (defstruct struct-name ...)
>>   (defstruct (struct-name OPTIONS) ...)
>
> Also for defun in Common-Lisp, there's (defun (setf foo) ...) where
> the "setf" probably shouldn't be highlighted but the "foo" should.

The `setf' should be highlighted as a macro but not as function name as
it is right now.

>> Cc-ing emacs-devel to ask if that's ok to commit.
>
> Could explain what the patch does?

Instead of skipping over whitespace and opening parens between the
definition macro/function and the defined thing's name, it skips only
over whitespace but captures an optional opening paren.  If there's one,
then we don't font-lock with `font-lock-function-name-face'.

The valid cases where the definition macro/function defines a type like
in `cl-defstruct' still highlights the symbol after the paren (but in
`font-lock-type-face').

Or in simpler words: if the name appears after an opening paren, that
cannot be a function name so don't font-lock as such.

Bye,
Tassilo



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

* Re: Concern around use of eval
       [not found]     ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
@ 2015-03-20 19:54       ` Joost Kremers
  0 siblings, 0 replies; 17+ messages in thread
From: Joost Kremers @ 2015-03-20 19:54 UTC (permalink / raw)
  To: help-gnu-emacs

Tassilo Horn wrote:
> Joost Kremers <joost.m.kremers@gmail.com> writes:
>
>> Why not do it at the top level directly? E.g.:
>>
>> ,----
>> | (defvar lh/labels '("label1" "label2" "label3"))
>> | 
>> | (defmacro lh/gen-predicate (label)
>> |   `(defun ,(intern (concat "lh/" label "-p")) ()
>> |      (member ,label *lh/system-label-store*)))
>> | 
>> | (mapc (lambda (label)
>> |         (lh/gen-predicate label))
>> |       lh/labels)
>> `----
>
> That won't work because.  When reading the mapc form, emacs sees that
> `lh/gen-predicate' is a macro and tries to expand it with the symbol
> label as argument.  The macroexpansion takes place before the actual
> execution of the code.

Thanks, that explains a few things.


-- 
Joost Kremers                                   joostkremers@fastmail.fm
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)


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

* Re: Bug in Elisp font-locking
  2015-03-20 18:47         ` Tassilo Horn
@ 2015-03-20 20:38           ` Stefan Monnier
  2015-03-20 22:45             ` Tassilo Horn
  0 siblings, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2015-03-20 20:38 UTC (permalink / raw)
  To: emacs-devel; +Cc: help-gnu-emacs

>> Could explain what the patch does?
[...]
> Or in simpler words: if the name appears after an opening paren, that
> cannot be a function name so don't font-lock as such.

OK, that sounds right for *Lisp,


        Stefan



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

* Re: Bug in Elisp font-locking
  2015-03-20 20:38           ` Stefan Monnier
@ 2015-03-20 22:45             ` Tassilo Horn
  2015-03-21  0:06               ` Johan Bockgård
  2015-03-21  2:33               ` Stefan Monnier
  0 siblings, 2 replies; 17+ messages in thread
From: Tassilo Horn @ 2015-03-20 22:45 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs, emacs-devel

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>>> Could explain what the patch does?
> [...]
>> Or in simpler words: if the name appears after an opening paren, that
>> cannot be a function name so don't font-lock as such.
>
> OK, that sounds right for *Lisp,

I've committed the patch for elisp, and just now also for CL after
scratching my head why its regex explicitly handled "(setf <symbol>" as
function name.  Aha, that's a setf-expander.  Learned something
again. :-)

Bye,
Tassilo



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

* Re: Bug in Elisp font-locking
  2015-03-20 22:45             ` Tassilo Horn
@ 2015-03-21  0:06               ` Johan Bockgård
  2015-03-21  7:26                 ` Tassilo Horn
  2015-03-21  2:33               ` Stefan Monnier
  1 sibling, 1 reply; 17+ messages in thread
From: Johan Bockgård @ 2015-03-21  0:06 UTC (permalink / raw)
  To: emacs-devel

Tassilo Horn <tsdh@gnu.org> writes:

> I've committed the patch for elisp, and just now also for CL after
> scratching my head why its regex explicitly handled "(setf <symbol>" as
> function name.

It *is* a function name, and you can use it like this:  #'(setf foo)

> Aha, that's a setf-expander.

Actually a "setf function", not a "setf expander".



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

* Re: Bug in Elisp font-locking
  2015-03-20 22:45             ` Tassilo Horn
  2015-03-21  0:06               ` Johan Bockgård
@ 2015-03-21  2:33               ` Stefan Monnier
  2015-03-21  7:55                 ` Tassilo Horn
  1 sibling, 1 reply; 17+ messages in thread
From: Stefan Monnier @ 2015-03-21  2:33 UTC (permalink / raw)
  To: help-gnu-emacs; +Cc: emacs-devel

> scratching my head why its regex explicitly handled "(setf <symbol>" as
> function name.  Aha, that's a setf-expander.  Learned something
> again. :-)

It's supported for cl-defmethod, by the way.


        Stefan




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

* Re: Bug in Elisp font-locking
  2015-03-21  0:06               ` Johan Bockgård
@ 2015-03-21  7:26                 ` Tassilo Horn
  0 siblings, 0 replies; 17+ messages in thread
From: Tassilo Horn @ 2015-03-21  7:26 UTC (permalink / raw)
  To: emacs-devel

Johan Bockgård <bojohan@gnu.org> writes:

Hi Johan,

>> I've committed the patch for elisp, and just now also for CL after
>> scratching my head why its regex explicitly handled "(setf <symbol>" as
>> function name.
>
> It *is* a function name, and you can use it like this: #'(setf foo)

Interesting.

>> Aha, that's a setf-expander.
>
> Actually a "setf function", not a "setf expander".

Ah, yes.  Searching the net, I found out these setf functions are an
alternative to setf expanders for simpler cases.  Neat.  But we don't
have them in Elisp, not even in cl-defun, right?

Bye,
Tassilo



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

* Re: Bug in Elisp font-locking
  2015-03-21  2:33               ` Stefan Monnier
@ 2015-03-21  7:55                 ` Tassilo Horn
  0 siblings, 0 replies; 17+ messages in thread
From: Tassilo Horn @ 2015-03-21  7:55 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: emacs-devel

Stefan Monnier <monnier@iro.umontreal.ca> writes:

>> scratching my head why its regex explicitly handled "(setf <symbol>"
>> as function name.  Aha, that's a setf-expander.  Learned something
>> again. :-)
>
> It's supported for cl-defmethod, by the way.

Ah, there we have our counter-example.  Oh well, `cl-defmethod' isn't
listed as a defining keyword anyhow.  eieio's `defmethod' OTOH is, but
that doesn't seem to support (setf name), at least its docs don't
mention it.  So I guess the cl-version should be added since the eieio
version is marked as obsolete.

Anyhow, I've now added cl-defmethod as cl-lib definier and added the
(setf symbol) stuff also for elisp.

Bye,
Tassilo



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

end of thread, other threads:[~2015-03-21  7:55 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-19  6:53 Concern around use of eval Les Harris
2015-03-19  8:00 ` Tassilo Horn
     [not found] ` <mailman.2302.1426752018.31049.help-gnu-emacs@gnu.org>
2015-03-19  8:12   ` Joost Kremers
2015-03-19  8:31     ` Tassilo Horn
     [not found]     ` <mailman.2305.1426753885.31049.help-gnu-emacs@gnu.org>
2015-03-20 19:54       ` Joost Kremers
2015-03-19 14:07 ` Stefan Monnier
2015-03-20 15:17   ` Thierry Volpiatto
2015-03-20 17:19     ` Bug in Elisp font-locking (was: Concern around use of eval) Tassilo Horn
2015-03-20 17:31       ` Bug in Elisp font-locking Stefan Monnier
2015-03-20 17:43         ` Drew Adams
2015-03-20 18:47         ` Tassilo Horn
2015-03-20 20:38           ` Stefan Monnier
2015-03-20 22:45             ` Tassilo Horn
2015-03-21  0:06               ` Johan Bockgård
2015-03-21  7:26                 ` Tassilo Horn
2015-03-21  2:33               ` Stefan Monnier
2015-03-21  7:55                 ` Tassilo Horn

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.