From: sickfaichezi
Subject: Macros and Evaluation
Date: 
Message-ID: <1139609522.781075.231640@o13g2000cwo.googlegroups.com>
Recently I ran across the following

"EVAL. Novices almost always misuse EVAL. When experts use EVAL, they
often would be better off using APPLY, FUNCALL, or SYMBOL-VALUE. Use of
EVAL when defining a macro should set off a warning bell -- macro
definitions are already evaluated during expansion. See also the answer
to question 3-12. The general rule of thumb about EVAL is: if you think
you need to use EVAL, you're probably wrong."

from the page http://www.lisp.org/table/style.htm on Lisp Programming
style.

Now I have a program where I would like to take an object and define a
constant based on fields of the object.

Heres the code for a macro that does exactly what I want, but it USES
EVAL:

(defmacro property-type-to-defconstant-code-mac (property-type)
  `(defconstant
     ,(intern (concatenate 'string "+" (slot-value (eval property-type)
'property-type-code) "+"))
     ,(slot-value (eval property-type) 'property-type-id)
     ,(slot-value (eval property-type) 'description)))

Now, I couldn't figure out a way to do this without using eval within a
macro, but then again, I am just a novice when it comes to lisp. So, is
this a case where eval should be used in a macro or does anyone out
there have a more elegant solution?

thanks
in advance.

From: Kaz Kylheku
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <1139615054.112055.238230@g43g2000cwa.googlegroups.com>
sickfaichezi wrote:
> Recently I ran across the following
>
> "EVAL. Novices almost always misuse EVAL. When experts use EVAL, they
> often would be better off using APPLY, FUNCALL, or SYMBOL-VALUE. Use of
> EVAL when defining a macro should set off a warning bell -- macro
> definitions are already evaluated during expansion. See also the answer
> to question 3-12. The general rule of thumb about EVAL is: if you think
> you need to use EVAL, you're probably wrong."
>
> from the page http://www.lisp.org/table/style.htm on Lisp Programming
> style.
>
> Now I have a program where I would like to take an object and define a
> constant based on fields of the object.
>
> Heres the code for a macro that does exactly what I want, but it USES
> EVAL:
>
> (defmacro property-type-to-defconstant-code-mac (property-type)
>   `(defconstant
>      ,(intern (concatenate 'string "+" (slot-value (eval property-type)
> 'property-type-code) "+"))
>      ,(slot-value (eval property-type) 'property-type-id)
>      ,(slot-value (eval property-type) 'description)))
>
> Now, I couldn't figure out a way to do this without using eval within a
> macro, but then again, I am just a novice when it comes to lisp. So, is
> this a case where eval should be used in a macro or does anyone out
> there have a more elegant solution?

How about a macro which generates a PROGN?

The first element of the PROGN is a DEFMACRO whose job is to generate a
DEFCONSTANT. This macro is customized with material from the
surrounding macro.

The second element of the PROGN is a call to the macro that was just
defined.

Ready?

(defmacro write-and-call-defconstant-writing-macro
(expr-evaluating-to-object)
  (let ((macro-name (gensym "WRITE-DEFCONSTANT-")))
    `(progn
       (defmacro ,macro-name ()
         (let ((name (intern (compute-name-from
,expr-evaluating-to-object)))
               (val (compute-value-from ,expr-evaluating-to-object)))
            `(defconstant ,name ,val)))
       (,macro-name))))

The COMPUTE-NAME-FROM and COMPUTE-VALUE-FROM are abstractions which
take your object and retrieve a string, or the value to use for the
defconstant.

In your actual code you'd replace these with slot accesses to the
object or whatever.

Also, it's probably a good idea to eliminate the double evaluation of
EXPR-EVALUATING-TO-OBJECT which is easy enough to do.

But of course, all we have done is avoid calling EVAL by name. We have
swept it under the rug.
From: Joerg Hoehle
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <uwtfgk8uc.fsf@users.sourceforge.net>
"Kaz Kylheku" <········@gmail.com> writes:
> The first element of the PROGN is a DEFMACRO whose job is to generate a
> DEFCONSTANT. This macro is customized with material from the
> surrounding macro.
> The second element of the PROGN is a call to the macro that was just
> defined.

MACROLET is what you could be using instead.
The expanded result is still top-level in ANSI-CL.

What about this?
(defmacro write-and-call (expr)
  `(macrolet
       ((gen (x)
	  (print`(defconstant ,(compute-name-from x) ,(compute-value-from x)))))
     (gen ,expr)))
(Remove print for production)

Regards,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Coby Beck
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <d%8Hf.1576$Be4.1386@clgrps13>
"sickfaichezi" <············@gmail.com> wrote in message 
·····························@o13g2000cwo.googlegroups.com...
> Recently I ran across the following
>
> "EVAL. Novices almost always misuse EVAL. When experts use EVAL, they
> often would be better off using APPLY, FUNCALL, or SYMBOL-VALUE. Use of
> EVAL when defining a macro should set off a warning bell -- macro
> definitions are already evaluated during expansion. See also the answer
> to question 3-12. The general rule of thumb about EVAL is: if you think
> you need to use EVAL, you're probably wrong."
>
> from the page http://www.lisp.org/table/style.htm on Lisp Programming
> style.
>
> Now I have a program where I would like to take an object and define a
> constant based on fields of the object.
>
> Heres the code for a macro that does exactly what I want, but it USES
> EVAL:
>
> (defmacro property-type-to-defconstant-code-mac (property-type)
>  `(defconstant
>     ,(intern (concatenate 'string "+" (slot-value (eval property-type)
> 'property-type-code) "+"))
>     ,(slot-value (eval property-type) 'property-type-id)
>     ,(slot-value (eval property-type) 'description)))

This really should be a function, that's all.  But when is it called?  Where 
does property-type cone from?  A sample usage is usually a big help in 
helping.

> Now, I couldn't figure out a way to do this without using eval within a
> macro, but then again, I am just a novice when it comes to lisp. So, is
> this a case where eval should be used in a macro or does anyone out
> there have a more elegant solution?

Normally what you should us is the , operator that will do the evaluation. 
You say this works?  Is property-type a special variable?  EVAL won't know 
any lexical bindings.  If this has worked for you maybe it is an artifact of 
some top level messing around you have done.

Also, beware of multiple evaluations of macro arguments (because of possible 
side effects in the evaluation).  If you need it more than once then use let 
and a local variable and the comma operator.

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")

> thanks
> in advance.
> 
From: sickfaichezi
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <1139622692.607386.74960@g43g2000cwa.googlegroups.com>
Hi Coby,

To supply a bit of context to the problem property-type is an object
returned from database query using the cl-sql package.

Since reading your reply, I've tried to turn it into the following
function

(defun property-type-to-defconstant-code-fun (property-type)
  (let ((symbol
           (intern (concatenate 'string "+" (slot-value property-type
'property-type-code) "+")))
        (value (slot-value property-type 'property-type-id))
        (documentation (slot-value property-type 'description)))
    (defconstant symbol value documentation)))

but I get the following error on compilation:

;   (LET (# # #)
;     (DEFCONSTANT SYMBOL VALUE DOCUMENTATION))
; Note: Variable SYMBOL defined but never used.
;
; Note: Variable DOCUMENTATION defined but never used.
;

and the following error when I try to call it

PROPERTYTYPES> (property-type-to-defconstant-code-fun (first (select
'PropertyType :flatp t)))

The value of #:G20 is DOCUMENTATION, which is not of type (OR STRING
NULL).
   [Condition of type SIMPLE-TYPE-ERROR]

Maybe using eval is the only solution.
From: Barry Margolin
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <barmar-97723A.21012410022006@comcast.dca.giganews.com>
In article <·······················@g43g2000cwa.googlegroups.com>,
 "sickfaichezi" <············@gmail.com> wrote:

> Hi Coby,
> 
> To supply a bit of context to the problem property-type is an object
> returned from database query using the cl-sql package.
> 
> Since reading your reply, I've tried to turn it into the following
> function
> 
> (defun property-type-to-defconstant-code-fun (property-type)
>   (let ((symbol
>            (intern (concatenate 'string "+" (slot-value property-type
> 'property-type-code) "+")))
>         (value (slot-value property-type 'property-type-id))
>         (documentation (slot-value property-type 'description)))
>     (defconstant symbol value documentation)))
> 
> but I get the following error on compilation:
> 
> ;   (LET (# # #)
> ;     (DEFCONSTANT SYMBOL VALUE DOCUMENTATION))
> ; Note: Variable SYMBOL defined but never used.
> ;
> ; Note: Variable DOCUMENTATION defined but never used.
> ;
> 
> and the following error when I try to call it
> 
> PROPERTYTYPES> (property-type-to-defconstant-code-fun (first (select
> 'PropertyType :flatp t)))
> 
> The value of #:G20 is DOCUMENTATION, which is not of type (OR STRING
> NULL).
>    [Condition of type SIMPLE-TYPE-ERROR]
> 
> Maybe using eval is the only solution.

In this case, it may be.  DEFCONSTANT is a macro that doesn't evaluate 
its first and third arguments, and there's no standard functional 
equivalent.  So if you need to compute the arguments to DEFCONSTANT at 
run time, you need to use EVAL:

(defun property-type-to-defconstant-code-fun (property-type)
  (let ...
    (eval `(defconstant ,symbol ',value ,documentation)))

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Coby Beck
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <FkcHf.1898$Be4.268@clgrps13>
"sickfaichezi" <············@gmail.com> wrote in message 
····························@g43g2000cwa.googlegroups.com...
> Hi Coby,
>
> To supply a bit of context to the problem property-type is an object
> returned from database query using the cl-sql package.
>
> Since reading your reply, I've tried to turn it into the following
> function
>
> (defun property-type-to-defconstant-code-fun (property-type)
>  (let ((symbol
>           (intern (concatenate 'string "+" (slot-value property-type
> 'property-type-code) "+")))
>        (value (slot-value property-type 'property-type-id))
>        (documentation (slot-value property-type 'description)))
>    (defconstant symbol value documentation)))
>
> but I get the following error on compilation:
>
> ;   (LET (# # #)
> ;     (DEFCONSTANT SYMBOL VALUE DOCUMENTATION))
> ; Note: Variable SYMBOL defined but never used.
> ;
> ; Note: Variable DOCUMENTATION defined but never used.
> ;
>
> and the following error when I try to call it
>
> PROPERTYTYPES> (property-type-to-defconstant-code-fun (first (select
> 'PropertyType :flatp t)))
>
> The value of #:G20 is DOCUMENTATION, which is not of type (OR STRING
> NULL).
>   [Condition of type SIMPLE-TYPE-ERROR]
>
> Maybe using eval is the only solution.

I suspect (this is a standard suspicion when someone is trying to create 
variable names at runtime) that you might be better off to have one special 
variable, perhaps a hash-table, and do something like
(setf (gethash (slot-value property-type 'property-type-id) 
*property-types*)
      (list (slot-value property-type 'property-type-code)
            (slot-value property-type 'description)))

Presumable some other code is going to try to retrieve this info, will it 
have to reconstruct this defconstant name?  Easier to retrieve stuff from a 
global hashtable.  I might ask why not store the whole property-type object? 
You can always right a nice interface to cover all those nuts and bolts eg:
(defun get-property-type-code (id)
   (first (gethash id *property-types*)))
etc.
then if you want to change things later (eg with the whole object in the 
hashtable) you just change your get function and callers don't know the 
difference.
(defun get-property-type-code (id)
   (property-type-code (gethash id *property-types*)))

99% of the time, "don't use eval" is correct and a good chunk of those times 
it's because of trying to construct variables at runtime.  Variable names 
are really for people, and at runtime people are not looking any more!

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: sickfaichezi
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <1139627434.293957.126830@z14g2000cwz.googlegroups.com>
Coby,

Yes, some other code is trying to retrieve this data, which brings me
to another question; Is it possible to dynamically export these
functions to other code through the package facility?

In reference to storing the whole object, I absolutely agree with you,
and that's actually what I've ended up doing.

Thanks for your help.
From: Coby Beck
Subject: Re: Macros and Evaluation
Date: 
Message-ID: <MzdHf.1910$Be4.994@clgrps13>
"sickfaichezi" <············@gmail.com> wrote in message 
·····························@z14g2000cwz.googlegroups.com...
> Coby,
>
> Yes, some other code is trying to retrieve this data, which brings me
> to another question; Is it possible to dynamically export these
> functions to other code through the package facility?

I think you can do any package stuff you want at run time, but I dare say 
this very likely represents a bad design choice!

> In reference to storing the whole object, I absolutely agree with you,
> and that's actually what I've ended up doing.
>
> Thanks for your help.

No worries!

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")