From: Tim Bradshaw
Subject: CASE and functions
Date: 
Message-ID: <ey3afczicnd.fsf@wiay.aiai.ed.ac.uk>
I have some (CL) code that needs to check if a function is one of a
small number of known ones (all of which are CL functions, in fact
they're +,-,*, or /.).  I quickly discovered that this:

	(ecase fn
	  (#'+ ...)
	  ...)

doesn't work, for obvious reasons.  What I'm using now is this:

      (ecase fn
	(#.#'+ '+)
	(#.#'- '-)
	(#.#'* '*)
	(#.#'/ '/))

which seems to work (and has the side benefit of having almost as high
a density of squiggly characters as perl, though I clearly need to be
working on my variable name squigglyness).

The question: is something like this going to work portably,
particularly is it going to work through compiling files & loading
them in different images &c?  I think it is, but whenever I try and
really understand just what literals you're allowed in CL I get
confused.

(I should, probably, have written my code to return symbols for the
arithmetic fns and then used a CASE to get the fns when I needed them,
but I'm slightly committed to this way of doing it now.

Thanks

--tim
From: Kent M Pitman
Subject: Re: CASE and functions
Date: 
Message-ID: <sfw67nnx976.fsf@world.std.com>
Tim Bradshaw <ยทยทยท@aiai.ed.ac.uk> writes:

[Amusing references to PERL that make me feel old because they
 are not instead references to Teco or APL removed.]

>       (ecase fn
> 	(#.#'+ '+)
> 	(#.#'- '-)
> 	(#.#'* '*)
> 	(#.#'/ '/))
[...]
> The question: is something like this going to work portably,
> particularly is it going to work through compiling files & loading
> them in different images &c?  I think it is, but whenever I try and
> really understand just what literals you're allowed in CL I get
> confused.

There are secretly several questions in play here...

 1) What can you use as a literal?  Answer: Well, QUOTE itself and
    being a program literal are not the bottleneck. If you cons a
    literal at runtime, you can use it freely [subject to other 
    caveats below, which really have nothing to do with the literal
    itself but rather the choice of which literal, etc.].

 2) The PROBLEM is externalizing program data to a file and reloading
    it, as happens in file compilation (for example).  Once you do
    this, the file compiler can only do so much for you.  See
    section 3.2.4 (Literal Objects in Compiled Files) in CLHS, 
    including its subsections on Externalizable Objects and
    Similarity of Literal Objects.  

    I assume you know CLHS is available at
    http://www.harlequin.com/education/books/HyperSpec/

    Anyway, I'd say you're on shakey ground with function objects
    being saved to files.  I wrote another reply (on the subject
    "*print-redably* and functions") to comp.lang.lisp within the
    last day addressing this problem, so you could read that, too.

 3) Last, I have the vaguest recollection that nowhere is it required
    (and perhaps somewhere it's warned about) that
           (eq #'+ #'+)
    That is, I have memory of some committee meeting in which someone
    made the claim that it would unfairly tie an implementors hands
    if he couldn't cons an object wrapper for function definitions 
    on the fly. I don't recall the outcome of this discussion, but
    I'm always leary of anything coming from #' or symbol-function
    having the same object-identity.  My guess is that this was some
    visitor from the Scheme camp who believes that functions are not
    important for their identity and shouldn't be defined under EQ
    at all (sort of like numbers aren't--perhaps a conncession to 
    Goedel :-).  Anyway, I' now unable to find a reference so I can't
    opine definitively on this right now.

> (I should, probably, have written my code to return symbols for the
> arithmetic fns and then used a CASE to get the fns when I needed them,
> but I'm slightly committed to this way of doing it now.

Probably.  But you know, this problem has to be solved by the implementors
in order to puzzle out the answer to the MAKE-HASH-TABLE problem, since
it takes either #'eq or 'eq  forms of arguments for the test.  So on a
case by case basis, there is a suitable (non-portable) solution.  Either
to just use the constant or to use a case on some (function-name op) where
function-name is a system-dependent symbol for getting a function's name.
(Not sure why we didn't provide you an operator for that... probably someone
thought it was debugging info that should be flushable to save space.)

Btw, if it's just these four functions, and you're REALLY SURE,
you could do

 (case (funcall op 6 3)
   ((9) ...)  ;+
   ((3) ...)  ;-
   ((18) ...) ;*
   ((2) ...)) ;/
   
:-)

But the best solution might be to write a case macro variant that
allows you to have an evaluated form there, or even just to use cond.
My bet is that most serious Lisp implementations will not actually
run you into problem 3 above, and maybe I'm just misremembering that
it is a problem at all.  Which means you can be "mostly portable"
with:

 (cond ((eq op #'+) ...)
       ((eq op #'-) ...)
       ((eq op #'*) ...)
       ((eq op #'/) ...))

Hope this helps.
 --Kent