From: An Metet
Subject: Avoiding eval
Date: 
Message-ID: <a26c36cc4df397b69f8676ea803c0504@anonymous.poster>
NOTE: This message was sent thru a mail2news gateway.
No effort was made to verify the identity of the sender.
--------------------------------------------------------

*Total-Amateur*
I am trying to avoid using eval etc. while re-writing some code and attempting
my first use of object orientation,
I have a feeling this should be done with a macro but my many attemps to do this
have all resulted in failure.
The approaches attempted include accepting symbols as arguments
and nesting macro's to use the ,@ feature for the arg-list
The code below seems to work but includes the use of eval
Could somebody please show me how it should be done?

(defparameter *category-list* 
  '( "mollusc" "fish" "insect" "mammal" "bird" "fish" "arachnid" "reptile" "amphibian")) 
(defparameter *opt-a-list*    
  '( "walking" "flying" "swimming" "crawling"))
(defparameter *opt-b-list* 
  '("wild" "domesticated" "extinct"))
(pprint (setq arg-list 
              (concatenate 'list
                           (mapcar #'list *category-list*)
                           (mapcan #'(lambda(X)
                                       (mapcar #'(lambda (Y)
                                                   (list X :opt-a Y ))
                                               *opt-a-list*)) 
                                   *category-list*)
                           (mapcan #'(lambda(X)
                                       (mapcar #'(lambda (Z)
                                                   (list X :opt-b Z ))
                                               *opt-b-list*)) 
                                   *category-list*)
                           (mapcaN #'(lambda(X)
                                       (mapcan #'(lambda(Y)
                                                   (mapcar #'(lambda (Z)
                                                               (list X :opt-a Y :opt-b Z ))
                                                           *opt-b-list*))
                                               *opt-a-list*)) 
                                   *category-list*))))
(defun Item-classf (category &optional &key opt-a  opt-b)
  (let* ((sym-category (read-from-string category))
         (sym-class nil))
    (cond ((and category opt-a opt-b)
           (let ((sym-opt-a (read-from-string opt-a))
                 (sym-opt-b (read-from-string opt-b)))
             (setf sym-class 
                   (read-from-string 
                    (concatenate 'string category "-"  opt-a "-" opt-b)))
             (eval `(defclass ,sym-class (common ,sym-category ,sym-opt-a  ,sym-opt-b )() ))))

          ((and category opt-a )
           (let ((sym-opt-a (read-from-string opt-a)))
             (setf sym-class (read-from-string (concatenate 'string category "-" opt-a)))
             (eval `(defclass ,sym-class (common ,sym-category ,sym-opt-a )() ))))

          ((and category opt-b ) 
           (let ((sym-opt-b (read-from-string opt-b))) 
             (setf sym-class (read-from-string (concatenate 'string category "-" opt-b)))
             (eval `(defclass ,sym-class (common ,sym-category ,sym-opt-b )() ))))

          (category 
           (setf sym-class sym-category) 
           (eval `(defclass ,sym-class (common ,sym-category )() )))

          (T         "Oopsies"))
    
    (print (find-class sym-class))))

(dolist (args arg-list "done") (apply #'item-classf args))
---
Try Anything Twice

From: Erann Gat
Subject: Re: Avoiding eval
Date: 
Message-ID: <gNOSPAMat-1702042055520001@192.168.1.51>
In article <································@anonymous.poster>, An Metet
<·························@[127.1]> wrote:

> *Total-Amateur*

You underestimate yourself.

> I am trying to avoid using eval etc. while re-writing some code and attempting
> my first use of object orientation,
> I have a feeling this should be done with a macro

Your feeling is correct.

> but my many attemps to do this
> have all resulted in failure.

Why don't you post your failed attempts?

I don't have time to look at your code in detail at the moment (Frasier is
about to come on :-)  but as a first cut I'd try just changing defun to
defmacro and simply deleting the evals.  That looks like it might just
work.

E.
From: starwars
Subject: RE: Avoiding eval
Date: 
Message-ID: <6062a664d98409660b33be8b264e441d@tatooine.homelinux.net>
Thanks Erann,
  Yes, the resulting macro worked.
 The function posted was a conversion from a macro so I
should not be too supprised. It probably had always worked.
The error was in how I was trying to use it. Your vote of confidence
in the code allowed me to look harder for (and find) a problem elswhere.

Just prior to posting , I wiped all the failed code because I was convinced
I had a program that worked. This illusion was dispelled once previously
created classes were eliminated.

---
Try Anything Twice
From: Erann Gat
Subject: Re: Avoiding eval
Date: 
Message-ID: <gNOSPAMat-1902041939470001@192.168.1.51>
In article <································@tatooine.homelinux.net>,
starwars <··································@[127.1]> wrote:

> Thanks Erann,
>   Yes, the resulting macro worked.

Woo hoo!  :-)

>  The function posted was a conversion from a macro so I
> should not be too supprised. It probably had always worked.
> The error was in how I was trying to use it. Your vote of confidence
> in the code allowed me to look harder for (and find) a problem elswhere.

Glad I could help.

E.
From: edo
Subject: RE: Avoiding eval
Date: 
Message-ID: <113f1942f70271a098c1cc50aae679fe@cryptorebels.net>
Thanks Kaz,
All the required info will be available at compile time,
The criteria for poor eval use were filled.
I fixed up the macro version as per your suggestions, INTERN etc.

I had tried to use APPLY on my macro but it failed

(dolist (args arg-list "done") (apply #'item-classm args));fails
But entering the arguments directly works.

ITEM-CLASSF was created by ediding  ITEM-CLASSM a little
in desperation.

I got a bit confused with all the backquotes quotes commas comma-ats
while trying to work around this so I built the lists without them.

(defmacro list-feed (macro x)
  (append  (list 'progn) 
           (do ((n (- (length (symbol-value x))1) (decf n))
                (acc '())
                (args '() '()))
               ((= n -1) acc)
             (setf args (nth n (symbol-value x)))
             (push macro args)
             (push args acc))))

(list-feed item-classm arg-list) ==> success

I suspect that this codes immediate ancestor would not have worked
but I couldn't find out as it caused lispworks to exit abruptly

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;WARNING, CODE CAUSES LISPWORKS TO EXIT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro list-feed (macro x)  
           (do ((n (- (length (symbol-value x))1) (decf n))
                (acc '())
                (args '() '()))
               ((= n -1) (values-list acc))
             (setf args (nth n (symbol-value x)))
             (push macro args)
             (push args acc)))

(list-feed item-classm arg-list) ==> ABRUPT EXIT

---
Try Anything Twice
From: Thomas A. Russ
Subject: Re: Avoiding eval
Date: 
Message-ID: <ymioerttvje.fsf@sevak.isi.edu>
edo <··································@[127.1]> writes:

> I suspect that this codes immediate ancestor would not have worked
> but I couldn't find out as it caused lispworks to exit abruptly

If you aren't aware of it, you may find that MACROEXPAND and
MACROEXPAND-1 useful functions when trying to debug your macros.  What
they do is expand macros and return the result of the expansion.  This
is a bit different than just invoking the macro, which attempts to
execute the expansion.  Since it is one step earlier in the process you
may be able to find problems.  It also lets you confirm that your macro
is actually generating the code that you want it to do

> (list-feed item-classm arg-list) ==> ABRUPT EXIT

So instead you would use

(macroexpand-1 '(list-feed item-classm arg-list))

Note the QUOTE in front of the macro form.  It's crucial. :)


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Thomas A. Russ
Subject: Re: Avoiding eval
Date: 
Message-ID: <ymin07dtv9f.fsf@sevak.isi.edu>
edo <··································@[127.1]> writes:

> I had tried to use APPLY on my macro but it failed
> 
> (dolist (args arg-list "done") (apply #'item-classm args));fails
> But entering the arguments directly works.

How did it fail?

> I got a bit confused with all the backquotes quotes commas comma-ats
> while trying to work around this so I built the lists without them.
> 
> (defmacro list-feed (macro x)
>   (append  (list 'progn) 
>            (do ((n (- (length (symbol-value x))1) (decf n))
>                 (acc '())
>                 (args '() '()))
>                ((= n -1) acc)
>              (setf args (nth n (symbol-value x)))
>              (push macro args)
>              (push args acc))))

A couple of comments.

One is that using (cons 'progn ...) would be a bit more efficient than
(append (list 'progn) ...).  Although append is quite a handy function,
it hides a lot of list copying and is often a hidden performance drain
for novice lisp programmers.

Second is that using a global value of a variable passed in to the macro
is a bad idea.  It would be better to provide the value of the global
directly to the macro instead of indirecting through the global.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: An Metet
Subject: RE: Avoiding eval
Date: 
Message-ID: <fb164009e6e6a6d7e3be996600fa1445@anonymous.poster>
NOTE: This message was sent thru a mail2news gateway.
No effort was made to verify the identity of the sender.
--------------------------------------------------------

>From: ···@sevak.isi.edu (Thomas A. Russ)

>> I had tried to use APPLY on my macro but it failed
>> 
>> (dolist (args arg-list "done") (apply #'item-classm args));fails
>> But entering the arguments directly works.
>
>How did it fail?

The question suggests that you think it should work,
I was quite dissapointed when it didn't.

It Fails just like this

CL-USER 6 > (item-classm "testname")
#<STANDARD-CLASS |testname| 2067DD3C>

CL-USER 7 > (macroexpand-1 '(item-classm "testname"))
(DEFCLASS |testname| (COMMON |testname|) NIL)
T

CL-USER 8 > (dolist (args arg-list "done") (apply #'item-classm args))

Error: Call ((LAMBDA (#:%%MACROARG%% #:&ENVIRONMENT525 &AUX 
(#:&WHOLE526 #:%%MACROARG%%) (#:\(CATEGORY\ ...\)527 #) 
(#:CHECK-LAMBDA-LIST-TOP-LEVEL531 #) (#:CATEGORY #) (#:KEYS528 #)
(#:SUPPLIED-P529 #) (#:OPT-A #) (#:SUPPLIED-P530 #) (#:OPT-B #)) 
(DECLARE (SPECIAL:SOURCE #) (LAMBDA-LIST CATEGORY &KEY OPT-A OPT-B))
(BLOCK #:ITEM-CLASSM (LET # #))) "mollusc") has the wrong number of arguments.
  1 (abort) Return to level 0.
  2 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other options

CL-USER 9 : 1 > 


The macro ITEM-CLASSM has optional keyword arguments and it apears to me
as if they are being treat as "REQUIRED" when using the macro in this way.

Below is the ITEM-CLASSM macro and code for the argument lists repeated

(defparameter *category-list* 
  '( "mollusc" "fish" "insect" "mammal" "bird" "fish" "arachnid" "reptile" "amphibian")) 
(defparameter *opt-a-list*    
  '( "walking" "flying" "swimming" "crawling"))
(defparameter *opt-b-list* 
  '("wild" "domesticated" "extinct"))
(pprint (setq arg-list 
              (concatenate 'list
                           (mapcar #'list *category-list*)
                           (mapcan #'(lambda(X)
                                       (mapcar #'(lambda (Y)
                                                   (list X :opt-a Y ))
                                               *opt-a-list*)) 
                                   *category-list*)
                           (mapcan #'(lambda(X)
                                       (mapcar #'(lambda (Z)
                                                   (list X :opt-b Z ))
                                               *opt-b-list*)) 
                                   *category-list*)
                           (mapcaN #'(lambda(X)
                                       (mapcan #'(lambda(Y)
                                                   (mapcar #'(lambda (Z)
                                                               (list X :opt-a Y :opt-b Z ))
                                                           *opt-b-list*))
                                               *opt-a-list*)) 
                                   *category-list*))))

(defmacro Item-classm (category &key opt-a opt-b)
  (let ((sym-category (intern category))
         (sym-class nil))

    (cond ((and category opt-a opt-b)
           (let ((sym-opt-a   (intern opt-a))
                 (sym-opt-b   (INTERN opt-b)))
             (setf sym-class 
                   (INTERN 
                    (concatenate 'string category "-"  opt-a "-" opt-b)))
             `(defclass ,sym-class (common ,sym-category ,sym-opt-a  ,sym-opt-b )() )))

          ((and category opt-a )
           (let ((sym-opt-a   (INTERN opt-a)))
             (setf sym-class (INTERN (concatenate 'string category "-" opt-a)))
             `(defclass ,sym-class (common ,sym-category ,sym-opt-a )() )))
             
          ((and category opt-b ) 
           (let ((sym-opt-b   (INTERN opt-b))) 
             (setf sym-class (INTERN (concatenate 'string category "-" opt-b)))
             `(defclass ,sym-class (common ,sym-category ,sym-opt-b )() )))
             
          (category 
           (setf sym-class sym-category) 
           `(defclass ,sym-class (common ,sym-category )() ))
           
          (T         "Oopsies"))));learn about condition system



---
Try Anything Twice
From: Kenny Tilton
Subject: Re: Avoiding eval
Date: 
Message-ID: <Tof_b.162325$cM1.31041605@twister.nyc.rr.com>
An Metet wrote:
> NOTE: This message was sent thru a mail2news gateway.
> No effort was made to verify the identity of the sender.
> --------------------------------------------------------
> 
> 
>>From: ···@sevak.isi.edu (Thomas A. Russ)
> 
> 
>>>I had tried to use APPLY on my macro but it failed
>>>
>>>(dolist (args arg-list "done") (apply #'item-classm args));fails
>>>But entering the arguments directly works.
>>
>>How did it fail?
> 
> 
> The question suggests that you think it should work,
> I was quite dissapointed when it didn't.

That might have been a rhetorical question, thinking it was failing this 
way (from acl62):

CELLO(1): (defmacro does-not-apply (x)
             `(print ,x))
DOES-NOT-APPLY
CLO(2): (apply 'does-not-apply (list 42))
Error: Attempt to call DOES-NOT-APPLY which is defined as a macro.
[condition type: PROGRAM-ERROR]

macros cannot be APPLY'ed or funcalled.

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Thomas A. Russ
Subject: Re: Avoiding eval
Date: 
Message-ID: <ymihdxhtzjn.fsf@sevak.isi.edu>
An Metet <·························@[127.1]> writes:

> 
> NOTE: This message was sent thru a mail2news gateway.
> No effort was made to verify the identity of the sender.
> --------------------------------------------------------
> 
> >From: ···@sevak.isi.edu (Thomas A. Russ)
> 
> >> I had tried to use APPLY on my macro but it failed
> >> 
> >> (dolist (args arg-list "done") (apply #'item-classm args));fails
> >> But entering the arguments directly works.
> >
> >How did it fail?
> 
> The question suggests that you think it should work,
> I was quite dissapointed when it didn't.

Actually, I took you at your word and didn't expect it to work, but I
thought that the way it failed might prove to be instructive.  At the
very least, telling us what you find out can help focus our attention on
potential problems.  Since we're just volunteers, we (or at least I)
don't have a lot of time to spend on this list.

> It Fails just like this
> 
> CL-USER 6 > (item-classm "testname")
> #<STANDARD-CLASS |testname| 2067DD3C>
> 
> CL-USER 7 > (macroexpand-1 '(item-classm "testname"))
> (DEFCLASS |testname| (COMMON |testname|) NIL)
> T

OK, this looks rather suspicious, and is one reason to use macroexpand
to make sure your macro really is producing the code you want it to
produce.  If you look at the expansion, you will see that you are
defining a class which has itself as a superclass.  That isn't allowed.

So, you either need to generate a different classname (which is what I
assume below) or you need to recognize this case as building the base
class and exclude the category from the superclasses if there are no
options.

> 
> CL-USER 8 > (dolist (args arg-list "done") (apply #'item-classm args))
> 
> Error: Call ((LAMBDA (#:%%MACROARG%% #:&ENVIRONMENT525 &AUX 
> (#:&WHOLE526 #:%%MACROARG%%) (#:\(CATEGORY\ ...\)527 #) 
> (#:CHECK-LAMBDA-LIST-TOP-LEVEL531 #) (#:CATEGORY #) (#:KEYS528 #)
> (#:SUPPLIED-P529 #) (#:OPT-A #) (#:SUPPLIED-P530 #) (#:OPT-B #)) 
> (DECLARE (SPECIAL:SOURCE #) (LAMBDA-LIST CATEGORY &KEY OPT-A OPT-B))
> (BLOCK #:ITEM-CLASSM (LET # #))) "mollusc") has the wrong number of arguments.
>   1 (abort) Return to level 0.
>   2 Return to top loop level 0.
> 
> Type :b for backtrace, :c <option number> to proceed,  or :? for other options
> 
> CL-USER 9 : 1 > 
> 
> 
> The macro ITEM-CLASSM has optional keyword arguments and it apears to me
> as if they are being treat as "REQUIRED" when using the macro in this way.

First off, a macro is not a function, so you can't APPLY it.  But
instead of telling you that, your lisp is taking the macroexpansion
function and trying to apply that instead.  It is the wrong thing to do.

The fundamental rule is:  You Cannot APPLY or FUNCALL macros.

> Below is the ITEM-CLASSM macro and code for the argument lists repeated

Looking briefly at your macro, I notice that the result of the expansion
is basically the same with the only change being in the construction of
the list of superclasses and the name of the class.  That being the
case, I would structure things a little more simply, with auxiliary
functions.  One that computes the superclasses of the class you are
trying to define and another for the class name .  That also has the
advantage that you can test more parts of the code separately from the
command line and make sure they do what you want them to do.

For example:

(defun compute-superclasses (category opt-a opt-b)
  ;; Note that we build this list up backwards using PUSH
  (let ((supers nil))
    (when opt-b (push opt-b supers))
    (when opt-a (push opt-1 supers))
    (push category supers)
    ;; Alternately:  (when (or opt-b opt-a) (push category supers))
    ;; Use the alternative if you choose the other option to fixing
    ;;    the circular superclass problem.
    (push 'common supers)
    supers))

(defun compute-class-name (category opt-a opt-b)
  ;; Left as exercise for the reader.  Just extract the code
  ;; from your current macro.
  ;; NOTE:  MAKE SURE YOU MAKE A NAME DIFFERENT FROM THE category VALUE
  )

Then your macro becomes a lost simpler:

(defmacro Item-classm (category &key opt-a opt-b)
  `(defclass ,(compute-class-name category opt-a opt-b)
             ,(compute-superclasses category opt-a opt-b)))

This also assumes that you have replaced the lists with symbols.  That
will just simplify your programming:

(defparameter *category-list*
   '(mollusc fish insect mammal bird arachnid reptile amphibian))
(defparameter *opt-a-list*    
  '(walking flying swimming crawling))
(defparameter *opt-b-list* 
   '(wild domesticated extinct))

Then you invoke your macro like:

(item-classm insect :opt-a flying :opt-b wild)





> (defparameter *category-list* 
>   '( "mollusc" "fish" "insect" "mammal" "bird" "fish" "arachnid" "reptile" "amphibian")) 
> (defparameter *opt-a-list*    
>   '( "walking" "flying" "swimming" "crawling"))
> (defparameter *opt-b-list* 
>   '("wild" "domesticated" "extinct"))
> (pprint (setq arg-list 
>               (concatenate 'list
>                            (mapcar #'list *category-list*)
>                            (mapcan #'(lambda(X)
>                                        (mapcar #'(lambda (Y)
>                                                    (list X :opt-a Y ))
>                                                *opt-a-list*)) 
>                                    *category-list*)
>                            (mapcan #'(lambda(X)
>                                        (mapcar #'(lambda (Z)
>                                                    (list X :opt-b Z ))
>                                                *opt-b-list*)) 
>                                    *category-list*)
>                            (mapcaN #'(lambda(X)
>                                        (mapcan #'(lambda(Y)
>                                                    (mapcar #'(lambda (Z)
>                                                                (list X :opt-a Y :opt-b Z ))
>                                                            *opt-b-list*))
>                                                *opt-a-list*)) 
>                                    *category-list*))))
> 
> (defmacro Item-classm (category &key opt-a opt-b)
>   (let ((sym-category (intern category))
>          (sym-class nil))
> 
>     (cond ((and category opt-a opt-b)
>            (let ((sym-opt-a   (intern opt-a))
>                  (sym-opt-b   (INTERN opt-b)))
>              (setf sym-class 
>                    (INTERN 
>                     (concatenate 'string category "-"  opt-a "-" opt-b)))
>              `(defclass ,sym-class (common ,sym-category ,sym-opt-a  ,sym-opt-b )() )))
> 
>           ((and category opt-a )
>            (let ((sym-opt-a   (INTERN opt-a)))
>              (setf sym-class (INTERN (concatenate 'string category "-" opt-a)))
>              `(defclass ,sym-class (common ,sym-category ,sym-opt-a )() )))
>              
>           ((and category opt-b ) 
>            (let ((sym-opt-b   (INTERN opt-b))) 
>              (setf sym-class (INTERN (concatenate 'string category "-" opt-b)))
>              `(defclass ,sym-class (common ,sym-category ,sym-opt-b )() )))
>              
>           (category 
>            (setf sym-class sym-category) 
>            `(defclass ,sym-class (common ,sym-category )() ))
>            
>           (T         "Oopsies"))));learn about condition system




-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Barry Margolin
Subject: Re: Avoiding eval
Date: 
Message-ID: <barmar-30B8BD.06593918022004@comcast.ash.giganews.com>
In article <································@anonymous.poster>,
 An Metet <·························@[127.1]> wrote:

> I am trying to avoid using eval etc. while re-writing some code and 
> attempting
> my first use of object orientation,
> I have a feeling this should be done with a macro but my many attemps to do 
> this
> have all resulted in failure.

If you need to define classes at runtime, based on calculated data, then 
you need to EVAL a computed DEFCLASS form as you have, or use the MOP to 
call the underlying functions that DEFCLASS expands into.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Kaz Kylheku
Subject: Re: Avoiding eval
Date: 
Message-ID: <cf333042.0402180906.69edcf6d@posting.google.com>
An Metet <·························@[127.1]> wrote in message news:<································@anonymous.poster>...
> NOTE: This message was sent thru a mail2news gateway.
> No effort was made to verify the identity of the sender.
> --------------------------------------------------------
> 
> *Total-Amateur*
> I am trying to avoid using eval etc. while re-writing some code and attempting

You can only avoid using EVAL or COMPILE if you are using it in a
non-essential way.

There are at least two broad classes of poor EVAL use.

1. Dynamically evaluating something that is built out of inputs that
are all available at compile time. Such evals can be rearranged so
that they are evaluated when macros are expanded.

2. Using the backquote notation (or perhaps explicit list
construction) to generate the source code of function calls, and then
evaluating it to do the call. Such evals can be eliminated by learning
how to use APPLY. That is to say, you want (apply #'func x args)
rather than (eval `(func ,x ,@args)) or (eval (list* 'func x args)).

> my first use of object orientation,
> I have a feeling this should be done with a macro but my many attemps to do this
> have all resulted in failure.

It could be that the failure is because some of the inputs to your
computation are simply not available at macroexpansion time. In that
case, you can search for macro solutions until you are blue in the
face.

It becomes like the experimental search for a perpetual machine by
someone who does not know about the deeper principles at work:
thermodynamics, conservation of energy and heat losses due to
friction.

What you can do is use a macro to simplify some of your syntax, and do
some of the work at compile time. The resulting code still takes the
run-time inputs and completes the work, and that might require eval.
 
>                    (read-from-string 
>                     (concatenate 'string category "-"  opt-a "-" opt-b)))

I would not worry about EVAL if I'm also calling the reader and
interning symbols at run time!

Your use of READ-FROM-STRING is a roundabout way of calling the INTERN
function. You might want to do that directly to avoid the reader.

  (intern (concatenate 'string category "-" ...))

This is what the reader will do anyway---after doing all the hard work
of scanning the characters and extracting the token.

Plus by using INTERN directly, you avoid potential bugs. For example,
what if someone passes the string "(" as CATEGORY? Now your reader
will hit a syntax error, thinking it has an incomplete list. I can
even cause your code to do unwanted evaluation, if *READ-EVAL* has not
been turned off, by passing a CATEGORY that contains some #. notation.

INTERN does not interpret the string in any way. You get a symbol in
the current package whose name is that string, regardless of what that
string is.

>              (eval `(defclass ,sym-class (common ,sym-category ,sym-opt-a  ,sym-opt-b )() ))))

If you really need to make classes during the execution of your
program, you can't really avoid this. DEFCLASS works by calling
functions, but that interface is not standardized. There is a
meta-object protocol (MOP) which is not part of ANSI Common Lisp.
According to that protocol, DEFCLASS works by calling something called
ENSURE-CLASS, with arguments formed by transliterating the information
about the base classes and slots into a canonical form. You could
avoid EVAL by calling ENSURE-CLASS, but then your code would be less
portable. Why bother?

The question to ask yourself is whether you really need to introduce
new classes dynamically, based on run-time information. If not, then
you can package your code into a declarative macro language. That
language in effect becomes a specialized syntactic sugar for DEFCLASS
for concisely expressing the class ideas you are working with.

>           (T         "Oopsies"))

This calls for the condition system.
From: Thomas A. Russ
Subject: Re: Avoiding eval
Date: 
Message-ID: <ymismh8tb50.fsf@sevak.isi.edu>
Although not related to the question you asked, I wonder why you are
using strings for your various categories rather than symbols.

The other observation is that while READ-FROM-STRING will work to turn
strings into symbols respecting various readtable settings, a more
direct method is to use the INTERN function -- although you then need to
take more care about what case the string is in...



-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: George Orwell
Subject: Use of symbols for "words" -- was Avoiding eval
Date: 
Message-ID: <9765da6b7ce22b3eee01414059050e5e@mixmaster.it>
>Thomas A. Russ,  USC/Information Sciences Institute
>Although not related to the question you asked, I wonder why you are
>using strings for your various categories rather than symbols.

I get into lots of trouble using "Symbols" for two main reasons.
reading from a file may produce a list of tokens like
'(cat003.jpg 98E75432 212000 siamese may 1989 7.800)

1, the lisp  I am using decides if a token is a symbol, number or potential number
depending on its constituents. For instance '2e34 is treated as a number.
Some innocent looking tokens represent numbers so large lispworks 4.2 could
not swallow them with a read-base/print-base of 10.

What I think I need is a mechanism to cause lisp to interpret all tokens in context as
symbols. ie wrap the token in #\| 's and I have not figured out how.
 I have experimented with set-syntax-from-char to give digits alphabetic traits -
(did not work for me)
I also tried setting an illegal read-base but that did not work either.
I have not found the place which lisp uses to decide if a token is a number or a
symbol.

2, Interning everything in sight safely probably requires a knowledge of packages I do
not yet possess.

I have good control of the tokens being used in the current task, so I interpreted
 your question as a suggestion and used tokens instead. My function does not quite
do what I want...
It is o.k. for now but,
essential,   for more general use would be to have the number tokens reproduced
                   exactly as they appear in the token list,
nice,   would be to preserve case.

(Defun cat-tok-list (list &optional (sep-char ""))
  (if (eql (cdr list) nil) (car list)
    (intern (apply #'concatenate 'string
                   (let* ((Toks (Map 'list 'write-to-string list)) 
;; 'write-to-string stops an error when a number is encountered
;;but the string returned is not what I want 
;; using 'string causes an error when a number is encountered
;;but allows strings to be supplied as args
                          (Seps (fill (cdr (copy-list List)) (string sep-char)))
                          (stringarg (fill (copy-list List) 'string)))
                     (map-into toks #'concatenate stringarg toks seps))))))

(cat-tok-list '(aaa 2e45 bbb) #\-) ==>
AAA-2.0E45-BBB
NIL

desired result --> aaa-2e45-bbb

Do I perservere with the direction I am headed and perhaps use a
typecase function on each of the arguments then somehow arrange for the
any evaluation  to return what I want, trailing decimal zero's and all?
or is it a readtable thing?
Do I have to use strings if I can not guarantee the tokens are number free?

---
Try Anything Twice
From: Alan Crowe
Subject: Re: Use of symbols for "words" -- was Avoiding eval
Date: 
Message-ID: <86smglwlx5.fsf@cawtech.freeserve.co.uk>
George Orwell wrote:
> What I think I need is a mechanism to cause lisp to
> interpret all tokens in context as symbols. ie wrap the
> token in #\| 's and I have not figured out how.

I'm fairly new to Lisp myself, so don't take this as gospel,
but in response to your post I played around trying to write
my own read. It ought to be much easier if one doesn't have
to bother with converting numbers.

I got as far as

(defconstant consume-white-space t)

(defun termination(character)
  "test for things returned by read that terminate a symbol"
  (member character '(eof #\( #\) #\space #\newline #\tab #\linefeed )))

(defun read-rest-of-symbol (stream first-character)
  (let ((buffer (make-array 1
			    :element-type 'character
			    :fill-pointer 1
			    :initial-contents (list first-character))))
    (do ()
	((termination (peek-char nil stream nil 'eof)) (intern buffer))
	(vector-push-extend (read-char stream) buffer))))

(defun read-list (stream)
  "Called after #\( has been read"
  (peek-char consume-white-space stream)
  (do ((list '())
       (char (read-char stream)(progn
				 (peek-char consume-white-space stream)
				 (read-char stream))))
      ((char= char #\) ) (reverse list))
      (if (char= char #\( )
	  (push (read-list stream) list)
	(push (read-rest-of-symbol stream char) list))))

(defun read-once(&optional (stream *standard-input*))
  (peek-char consume-white-space stream)
  (let ((first-character (read-char stream)))
    (if (char= first-character #\( )
	(read-list stream)
      (read-rest-of-symbol stream first-character))))

Well, I started to get a little disheartened, because there
was a great deal more work to do if I wanted the fancy stuff
that read does, like putting in vectors and dotted lists. I
footled about and did

* (read)
(Alan 123 #.(read-once) (foo (1 3.0 (5d4 #c(0 1)))) more 2 + 2 = 5d4)

(ALAN 123 (|foo| (|1| |3.0| (|5d4| |#c| (|0| |1|)))) MORE 2 + 2 = 50000.0d0)

So putting in one #.(read-once) fetches you one S-expression
with all the interpretation turned off. Perhaps this is close
to what you are looking for?

Alan Crowe
Edinburgh
Scotland
From: Tim Bradshaw
Subject: Re: Use of symbols for "words" -- was Avoiding eval
Date: 
Message-ID: <fbc0f5d1.0403100337.2a7cc4b7@posting.google.com>
Alan Crowe <····@cawtech.freeserve.co.uk> wrote in message news:<··············@cawtech.freeserve.co.uk>...

> 
> I'm fairly new to Lisp myself, so don't take this as gospel,
> but in response to your post I played around trying to write
> my own read. It ought to be much easier if one doesn't have
> to bother with converting numbers.

Something like this is a pretty good approach.  If what you want is a
tokenizer that is less hairy than READ - however you end up
representing your tokens - I think it's quite often a good idea to
just write one, rather than try and coerce READ to do what you want
and preventing it doing what you don't.  If the input syntax is sane,
then writing one of these things is pretty easy.

--tim
From: An Metet
Subject: RE: Use of symbols for "words" -- was Avoiding eval
Date: 
Message-ID: <4b6d4b314f49a7b2e8223a3be8c5c6f3@anonymous.poster>
NOTE: This message was sent thru a mail2news gateway.
No effort was made to verify the identity of the sender.
--------------------------------------------------------

>So putting in one #.(read-once) fetches you one S-expression
>with all the interpretation turned off. Perhaps this is close
>to what you are looking for?
>
>Alan Crowe
>Edinburgh
>Scotland

Yes, it is, and many thanks,
This approach had not occurred to me at all, and I would have struggled
even if it had.
As an added benefit, I get to familiarise myself with some important aspects
of lisp which I have so far neglected.

bet its chilly up there in the Sharrow of The Bridge

Banks on it?

---
Try Anything Twice
From: Nomen Nescio
Subject: RE:  E. W. Dijkstra VS. John McCarthy.  A rebuttal to Paul Graham's web writings.
Date: 
Message-ID: <645c10fdaf1d651f50bbb4789338c254@dizum.com>
The Drafters I know who do programming use lisp (Autolisp).
All of the drafters I know use custom lisp programs hundreds of times every day.
Does this mean that C/C++/java must be headed for extinction - because nobody "I know about" uses them.

An easy to learn, lisp environment is provided within every release of Autocad, lisp expressions can be entered at the autocad command prompt. 

Lisp Rules - just ask any drafter