From: jmckitrick
Subject: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156026497.938079.279910@75g2000cwc.googlegroups.com>
I've discovered/started experimenting with intern and make-symbol.
Here's an instance where I might  use it.

I have a database with a record field that is a string naming the type
of record.  This type is used in case statements later on.  Right now,
thanks to the tutelage of Pascal, I'm doing this:

(intern (format nil ···@(~A~)" assessment-type))

to convert a string to a symbol.  But should I do this here?

Here are my choices, as I see them:

1.  Define all the types I need in my 'globals' list.  How do you
define a new type like this without using intern?

2.  Do the intern shown above, but into the keyword package.

3.  Don't change anything, and intern the assessment type when needed,
knowing later code that needs that symbol will find it already
interned.

BTW, I know I could do some fancy stuff with CLOS/CLSQL, but I don't
want to go that route right now.  I'm not ready to re-factor all my
CLSQL just yet.

From: Bill Atkins
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156041197.623827.311210@m73g2000cwd.googlegroups.com>
jmckitrick wrote:
> I've discovered/started experimenting with intern and make-symbol.
> Here's an instance where I might  use it.
>
> I have a database with a record field that is a string naming the type
> of record.  This type is used in case statements later on.  Right now,
> thanks to the tutelage of Pascal, I'm doing this:
>
> (intern (format nil ···@(~A~)" assessment-type))
>
> to convert a string to a symbol.  But should I do this here?
>
> Here are my choices, as I see them:
>
> 1.  Define all the types I need in my 'globals' list.  How do you
> define a new type like this without using intern?
>
> 2.  Do the intern shown above, but into the keyword package.
>
> 3.  Don't change anything, and intern the assessment type when needed,
> knowing later code that needs that symbol will find it already
> interned.
>
> BTW, I know I could do some fancy stuff with CLOS/CLSQL, but I don't
> want to go that route right now.  I'm not ready to re-factor all my
> CLSQL just yet.

I'm having a hard time understanding what you're asking.  Should you be
doing what where, and why would you think shouldn't?

Does  (intern (string-upcase "foo") :keyword) do what you're looking
for?

Can you explain what problem you're trying to solve?
From: jmckitrick
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156044964.167066.169860@75g2000cwc.googlegroups.com>
> I'm having a hard time understanding what you're asking.  Should you be
> doing what where, and why would you think shouldn't?
>
> Does  (intern (string-upcase "foo") :keyword) do what you're looking
> for?
>
> Can you explain what problem you're trying to solve?

I want a string in a database record to be converted to a type I can
use for 'case' statements.  I'm just not sure what is better:

a keyword type created from the string
a non-keyword type created from the string
From: Barry Margolin
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <barmar-85B046.00384120082006@comcast.dca.giganews.com>
In article <························@75g2000cwc.googlegroups.com>,
 "jmckitrick" <···········@yahoo.com> wrote:

> > I'm having a hard time understanding what you're asking.  Should you be
> > doing what where, and why would you think shouldn't?
> >
> > Does  (intern (string-upcase "foo") :keyword) do what you're looking
> > for?
> >
> > Can you explain what problem you're trying to solve?
> 
> I want a string in a database record to be converted to a type I can
> use for 'case' statements.  I'm just not sure what is better:

CASE statements don't use types.  Do you mean TYPECASE?  Or do you not 
really mean types?
 
> a keyword type created from the string
> a non-keyword type created from the string

Why not just do string comparisons:

(cond ((string-equal thing "foo") ...)
      ((string-equal thing "bar") ...)
      ...)

If you don't like writing that out for every case, you can define a 
STRING-CASE macro that does it, similar to the way CASE uses EQL.

However, if you really want to use symbols, I'd recommend keywords.

-- 
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: jmckitrick
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156049589.608187.107360@74g2000cwt.googlegroups.com>
Barry Margolin wrote:
> CASE statements don't use types.  Do you mean TYPECASE?  Or do you not
> really mean types?

If I say 'foo, then what is foo?

> Why not just do string comparisons:

That's what I did originally.  I'm experimenting right now.  Trying out
other solutions, some to learn, and others to see if they add
abstraction/remove redundancy.  I don't like to use string comparisons
in CL, if it can be avoided.  I save those for JavaScript.  :-)
From: Rob Warnock
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <b6KdnQDrrc_6oHXZnZ2dnUVZ_vudnZ2d@speakeasy.net>
jmckitrick <···········@yahoo.com> wrote:
+---------------
| Barry Margolin wrote:
| > Why not just do string comparisons:
| 
| That's what I did originally.  I'm experimenting right now.  Trying out
| other solutions, some to learn, and others to see if they add
| abstraction/remove redundancy.  I don't like to use string comparisons
| in CL, if it can be avoided.  I save those for JavaScript.  :-)
+---------------

It sounds very much like you're doing premature optimization
[which some say is the root of all programming evil, but that's
another story]. Do you really *KNOW* that a simple COND using
string comparisons is the main bottleneck in your application?
If not, forget your "likes" and just use it. This is especially
true if the number of distinct strings you have to deal with is
small and/or the average length is small.

If you just can't abide that [for whatever reason], and the
number of distinct strings is both small and *fixed* in your
application [you shouldn't be using CASE for data-driven
dispatch unless the number of distinct cases is fixed] then
using (CASE (INTERN (STRING-UPCASE db-field) :KEYWORD) ...cases...)
is certainly reasonable. That is:

    (case (intern (string-upcase db-field) :keyword)
      ((:foo)  (handle-a-foo))
      ((:bar)  (handle-a-bar))
      ((:quux) (handle-a-quux))
      (otherwise (handle-default-or-error db-field)))

A variant on that which is much more extensible is to make the
code executed by each branch of the CASE be a generic function
that uses an EQL specializer with a keyword value.

    (defmethod db-field-dispatch (key)
      ...code to handle input without an explicit handler...)

    (defmethod db-field-dispatch ((key (eql :foo)))
      (declare (ignore key))
      ...code to handle a "foo"...)

    (defmethod db-field-dispatch ((key (eql :bar)))
      (declare (ignore key))
      ...code to handle a "bar"...)

    (defmethod db-field-dispatch ((key (eql :quux)))
      (declare (ignore key))
      ...code to handle a "quux"...)

    ...other cases...

    ;; Call with:
    (db-field-dispatch (intern (string-upcase db-field) :keyword))

But if the number of cases is very large or needs to be even more
easily extensible, then what you probably want to do instead is
have an #'EQUAL hashtable that maps directly from an input string
to the function to handle that string, which you would call like
this, assuming you *didn't* need to pass the DB-FIELD to any of
the functions except the default/error handler.

    (flet ((default () (db-default-or-error db-field)))
      (funcall (gethash db-field *db-field-functions* #'default)))

Of course, if you changed the protocol so that you *always* pass
the DB-FIELD to all the functions [which you might want to do
anyway so you can have functions which handle multiple string
values], then it's a bit simpler:

    (funcall (gethash db-field *db-field-functions* #'db-default-or-error)
	     db-field)


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: jmckitrick
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156082295.268197.82360@h48g2000cwc.googlegroups.com>
Rob Warnock wrote:
> It sounds very much like you're doing premature optimization

I can't help myself.... ;-)

> If not, forget your "likes" and just use it. This is especially
> true if the number of distinct strings you have to deal with is
> small and/or the average length is small.

You're right. Only about 8 strings, one word each.

> using (CASE (INTERN (STRING-UPCASE db-field) :KEYWORD) ...cases...)

But the 'keyword' part answers part of my question, if it was better to
intern a plain symbol or a keyword.

> A variant on that which is much more extensible is to make the
> code executed by each branch of the CASE be a generic function
> that uses an EQL specializer with a keyword value.

That's pretty slick!  I've never tried specializing on anything other
than classes in the first argument slot, but I guess that's part of
what makes CLOS so great.
From: Barry Margolin
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <barmar-22EE93.07390820082006@comcast.dca.giganews.com>
In article <························@74g2000cwt.googlegroups.com>,
 "jmckitrick" <···········@yahoo.com> wrote:

> Barry Margolin wrote:
> > CASE statements don't use types.  Do you mean TYPECASE?  Or do you not
> > really mean types?
> 
> If I say 'foo, then what is foo?

It's a symbol.  Types are categories of objects like number, float, 
symbol, array, etc.

-- 
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: jmckitrick
Subject: Re: How best to intern arbitrary names/keywords
Date: 
Message-ID: <1156081717.198140.9410@b28g2000cwb.googlegroups.com>
Barry Margolin wrote:
> > If I say 'foo, then what is foo?
>
> It's a symbol.  Types are categories of objects like number, float,
> symbol, array, etc.

That's what I thought.  I only ask because 'case' is able to select
between several symbol values, just like typecase switches between
types.  But as I mentioned before, the whole string-to-symbol
conversion might be overkill.