From: ······@gmail.com
Subject: Convince me not to use eval
Date: 
Message-ID: <1190092676.214575.200490@n39g2000hsh.googlegroups.com>
So I'm new to LISP and even more-so to macros (as you can see by my
recent posts), but I know enough or have read enough to know that if
you're using eval, you're doing something wrong.

The macro takes a directory name and a filename (it's meant to be
called in a loop) and creates a global variable using defparameter
that is the filename with the 3rd character replaced with a '-' and
affixed with a '*' on either side.  I'm using ltk (lisp wrapper for
TK) and then take this new variable and load the actual filename onto
it.

And hey while we're at it - I hate to hardcode and would like to
replace the
(setf (aref var-name 2) #\-) line to something that replaces the last
(or all) '.' in a string with a '-' easily.  If you know one, let me
in on that too.

Well here's my code, and I cannot figure out how to get around using
eval:

(defmacro make-gif (dirname filename)
  `(let ((var-name (string-upcase ,filename)))
    (setf (aref var-name 2) #\-)
    (setf var-name (concatenate 'string "*" var-name "*"))
    (format t "var-name: ~a filename: ~a dirname:~a~%"
     var-name ,filename ,dirname)
    (eval `(defparameter ,(intern var-name) (make-image)))
    (eval `(image-load
            ,(intern var-name)
            ,(concatenate 'string ,dirname ,filename)))))

Thanks * Infinity,
JW

From: Tim Bradshaw
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <1190104896.766748.25670@g4g2000hsf.googlegroups.com>
On Sep 18, 6:17 am, ······@gmail.com wrote:

> (defmacro make-gif (dirname filename)
>   `(let ((var-name (string-upcase ,filename)))
>     (setf (aref var-name 2) #\-)
>     (setf var-name (concatenate 'string "*" var-name "*"))
>     (format t "var-name: ~a filename: ~a dirname:~a~%"
>      var-name ,filename ,dirname)
>     (eval `(defparameter ,(intern var-name) (make-image)))
>     (eval `(image-load
>             ,(intern var-name)
>             ,(concatenate 'string ,dirname ,filename)))))

You want the macro to look something like:

(defmacro define-gif (...)
  `(progn
     (defparameter ,(.. compute name ..) ...)
     (image-load ...))

Or if you want to you can raise the computation a bit:

(defmacro ...
  (let ...
    `(progn
       (defparameter ... things bound in the let ...)
       ...)))

Secondly (concatentate 'string ,dirname ,filename) is a horror: use
the pathname functions.

--tim
From: Kent M Pitman
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <uejgw1559.fsf@nhplace.com>
······@gmail.com writes:

> (defmacro make-gif (dirname filename)
>   `(let ((var-name (string-upcase ,filename)))
>     (setf (aref var-name 2) #\-)

Others have commented on the macro issues, so I won't bother with that.
I just want to point out that STRING-UPCASE is not guaranteed to make a
copy.  Per CLHS:

  For string-upcase, string-downcase, and string-capitalize, string is
  not modified. However, if no characters in string require
  conversion, the result may be either string or a copy of it, at the
  implementation's discretion.

  Source: http://www.lispworks.com/documentation/HyperSpec/Body/f_stg_up.htm#string-upcase
  
So when you're doing (SETF (AREF VAR-NAME 2) #]-) here, you're
here, you're potentially side-effecting a constant.  If I were you, I
might add
 (CHECK-TYPE FILENAME STRING "a literal string")
 (SETQ FILENAME (COPY-SEQ FILENAME))
at the top of the macro, before the backquote expression so you
have a safe space to work in.  (After doing that, you can use
NSTRING-UPCASE if the consing bothers you.)

[Of course, I think it's highly suspect to blindly replace the second
 character that way anyway.  But others have made this and other good 
 points, so I won't repeat them.]
From: Alex Mizrahi
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <46ef7292$0$90264$14726298@news.sunsite.dk>
(message (Hello ·······@gmail.com)
(you :wrote  :on '(Mon, 17 Sep 2007 22:17:56 -0700))
(

 j> Well here's my code, and I cannot figure out how to get around using
 j> eval:

uh, it's really weird -- you've made double macro, second with eval.
you don't even need a macro with it -- you could make it a function!

 j> (defmacro make-gif (dirname filename)
 j>   `(let ((var-name (string-upcase ,filename)))
 j>     (setf (aref var-name 2) #\-)
 j>     (setf var-name (concatenate 'string "*" var-name "*"))
 j>     (format t "var-name: ~a filename: ~a dirname:~a~%"
 j>      var-name ,filename ,dirname)
 j>     (eval `(defparameter ,(intern var-name) (make-image)))
 j>     (eval `(image-load
 j>             ,(intern var-name)
 j>             ,(concatenate 'string ,dirname ,filename)))))

you should move all computations out of generated code:

(defmacro make-gif (dirname filename)
 (let ((var-name (string-upcase filename)))
     (setf (aref var-name 2) #\-)
     (setf var-name (concatenate 'string "*" var-name "*"))
     (format t "var-name: ~a filename: ~a dirname:~a~%"
       var-name filename dirname)
   `(progn
      (defparameter ,(intern var-name) (make-image))
      (image-load ,(intern var-name) ,(concatenate 'string ,dirname 
,filename))))

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"Hanging In The Balance Of Deceit And Blasphemy") 
From: ··········@hotmail.com
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <1190100216.411457.211030@22g2000hsm.googlegroups.com>
1) A symbol that begins with the name MAKE-, sounds like something
that
   gives back an object and has no side-effects.
   Those are usually functions and doesn't use any DEF* macros/
functions.
   If you do want to have side-effects by calling defparameter, maybe
   calling it DEFINE-GIF is more proper ?

2) Perhaps get computation out of compiled code ?
   If you are calling MAKE-GIF with variables, Alex version will
break. Consider:
   (defmacro make-gif (foo)
     (format t "Compile-time:{~s}~%" foo)
     `(format t "Runtime:{~s}~%" ,foo))

   (make-gif "hi")
   (let ((bar "hi"))
     (make-gif bar))
From: Thomas A. Russ
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <ymibqbz99c6.fsf@blackcat.isi.edu>
······@gmail.com writes:

> So I'm new to LISP and even more-so to macros (as you can see by my
> recent posts), but I know enough or have read enough to know that if
> you're using eval, you're doing something wrong.
> 
> The macro takes a directory name and a filename (it's meant to be
> called in a loop) and creates a global variable using defparameter

Why?  What possible use is a global variable whose name is generated by
the macro?  That means that any code that wants to use that variable has
to already know in advance what it is.

If you want to keep some type of structure like this, it would be better
to use a single DEFPARAMETER that is bound to a hash-table with your
index entries.

BTW, this is a fairly common newbie design issue.  The ability to
manipulate symbols/identifiers in Lisp is much greater than in other
languages, and the use of the read-eval-print loop for interactive
development often leads to these sorts of (mis-)designs.

But a better solution is to use a hash-table, or (for small numbers of
items), an ALIST.

> that is the filename with the 3rd character replaced with a '-' and
> affixed with a '*' on either side.  I'm using ltk (lisp wrapper for
> TK) and then take this new variable and load the actual filename onto
> it.

OK.  I'm not familiar with LTK, so I don't know if it has some
requirement that a special variable be passed to the code.  Actually, I
seriously doubt it, and can see that from looking at the code.

> And hey while we're at it - I hate to hardcode and would like to
> replace the
> (setf (aref var-name 2) #\-) line to something that replaces the last
> (or all) '.' in a string with a '-' easily.  If you know one, let me
> in on that too.

Well, there's always SUBST.  But why even bother?  You can have any
characters you want in a Lisp symbol.  "." don't even require escaping,
so 

   MY-PICTURE.GIF  is a perfectly fine symbol name.  So is
   my-picture.gif but it will normally print as |my-picture.gif|

You can even have spaces in symbol names, so it is possible to have
valid lisp symbol named "My Picture.gif" which will print as
|My Picture.gif|


> Well here's my code, and I cannot figure out how to get around using
> eval:
> 
> (defmacro make-gif (dirname filename)
>   `(let ((var-name (string-upcase ,filename)))
>     (setf (aref var-name 2) #\-)
>     (setf var-name (concatenate 'string "*" var-name "*"))
>     (format t "var-name: ~a filename: ~a dirname:~a~%"
>      var-name ,filename ,dirname)
>     (eval `(defparameter ,(intern var-name) (make-image)))
>     (eval `(image-load
>             ,(intern var-name)
>             ,(concatenate 'string ,dirname ,filename)))))

Well, for starters, don't compute VAR-NAME at run-time.  Do it at
macro-expansion time.  One of the benefits of being able to use Lisp is
that you can run the lisp code to generate the expansion itself.  That
means you would pull the LET block outside the backquote.

Secondly, it is best to do your manipulation of directory and filenames
using the PATHNAME- functions in Common Lisp.  It will make your code
more portable.  (For even more portability, you might consider logical
pathnames, but even simple pathnames will work better.)

Actually you shouldn't even use a macro for this.  All you need is a
function call.  In fact, the function is really so simple that you
probably don't even need a separate function, but here is what you
really should be doing:

(defun get-gif (directory-list filename &optional (extension "gif"))
   "Returns an image from the directory (specified as a list of
   directory names) and the filename and extension."
   (image-load (make-image)
               (make-pathname :directory directory-list
                              :name filename
                              :type extension)))

(defparameter *my-image*
              (get-gif '("Documents" "Pictures" "My Vacation")
                       "beach-party"
                       "gif"))
      
Look ma, no EVALs. ;)

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Rainer Joswig
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <joswig-86DAB7.20395718092007@news-europe.giganews.com>
In article <···············@blackcat.isi.edu>,
 ···@sevak.isi.edu (Thomas A. Russ) wrote:

> Actually you shouldn't even use a macro for this.  All you need is a
> function call.  In fact, the function is really so simple that you
> probably don't even need a separate function, but here is what you
> really should be doing:
> 
> (defun get-gif (directory-list filename &optional (extension "gif"))
>    "Returns an image from the directory (specified as a list of
>    directory names) and the filename and extension."
>    (image-load (make-image)
>                (make-pathname :directory directory-list
>                               :name filename
>                               :type extension)))
> 
> (defparameter *my-image*
>               (get-gif '("Documents" "Pictures" "My Vacation")
>                        "beach-party"
>                        "gif"))
>       
> Look ma, no EVALs. ;)

Sometimes one might want a handle to all images.

It would be then useful to have a hashtable from
image names to image objects. One would create a
variable pointing to such a hashtable. Load an image
would then register the image under some name
in the hashtable. Then one can also provide
completion over image names for other operations
that take images as input.

It is not useful to use symbols in packages to
register named images. A hashtable is fine for that.

-- 
http://lispm.dyndns.org
From: Chris Russell
Subject: Re: Convince me not to use eval
Date: 
Message-ID: <1190111146.539434.266850@50g2000hsm.googlegroups.com>
On 18 Sep, 06:17, ······@gmail.com wrote:
> So I'm new to LISP and even more-so to macros (as you can see by my
> recent posts), but I know enough or have read enough to know that if
> you're using eval, you're doing something wrong.
>
> The macro takes a directory name and a filename (it's meant to be
> called in a loop) and creates a global variable using defparameter
> that is the filename with the 3rd character replaced with a '-' and
> affixed with a '*' on either side.  I'm using ltk (lisp wrapper for
> TK) and then take this new variable and load the actual filename onto
> it.
>
> And hey while we're at it - I hate to hardcode and would like to
> replace the
> (setf (aref var-name 2) #\-) line to something that replaces the last
> (or all) '.' in a string with a '-' easily.  If you know one, let me
> in on that too.
>
(map 'string [lambda(x)(if (char= x #\.) #\- x))var-name)

> Well here's my code, and I cannot figure out how to get around using
> eval:
----Snipped----

Ok, if I'm reading this correctly you're trying to use a macro inside
a loop.
As you're calling from inside a loop, the filename is being generated
inside the loop and not known till runtime, so you use eval to delay
the generation of the code till then.

Instead of doing this, if the parameters of the loop are known you can
unwrap the loop at compile time.

Replace (loop for i from 1 to 10 do (stuff i))  with a macro that
generates
`(progn
   ,@(loop for i from 1 to 10 collect `(stuff ,i)))
Then you can replace make-gif with Alex's version.