From: Georges KO
Subject: Some explanations on packages and symbols needed
Date: 
Message-ID: <m3zoin3vr4.fsf@symbiose.gko.net>
    Hello,

    Sorry for this FAQ, but I'm confused by packages and symbols...

1) let's say that I have a function my-func defined and exported in
   package A:

   (defun my-func (arg)
      (if (eq arg 'hello)
        t
        nil))

    when I call (my-func 'hello) from another package, I get nil. What
    did I miss ? Am I supposed to do things like (string= (symbol-name
    "HELLO") arg) ?

2) (it should be related to 1) if I do a (fboundp arg), I get also
   nil... (the fonction exists).

    Thank you.

    Georges.
-- 
 Georges KO (Taipei, Taiwan)                                      ···@gko.net
                D�cade I, Sextidi de Frimaire de l'Ann�e 209 de la R�volution

From: Kent M Pitman
Subject: Re: Some explanations on packages and symbols needed
Date: 
Message-ID: <sfwg0kfghm0.fsf@world.std.com>
Georges KO <···@gko.net> writes:

>     Sorry for this FAQ, but I'm confused by packages and symbols...

Not a problem.
 
> 1) let's say that I have a function my-func defined and exported in
>    package A:
> 
>    (defun my-func (arg)
>       (if (eq arg 'hello)
>         t
>         nil))
> 
>     when I call (my-func 'hello) from another package, I get nil. What
>     did I miss ? Am I supposed to do things like (string= (symbol-name
>     "HELLO") arg) ?

No.  That won't test symbol identity.  You MAY want to do that if what 
you want to test is same-name-p, but that will of course find other symbols
from other packages.  The correct thing is to export the symbol HELLO from
package A and then in package B do (MY-FUNC 'A:HELLO) if that's what you
want to do.  You'd do this if A:HELLO was part of a potentially arbitrary
namespace in which there might conceivably be a B:HELLO.  If you're confident
that there isn't going to be a conflict of this kind, and you just want a 
quick way to pass a name that doesn't require a string compare, the normal
thing is to pass a keyword, since keywords self-quote and are convenient to
type.  that is,
 in package A:
 (defun my-func (arg) 
   (if (eq arg :hello) t nil))
 in package B:
 (my-func :hello)

> 2) (it should be related to 1) if I do a (fboundp arg), I get also
>    nil... (the fonction exists).

(fboundp 'a:hello)

- - - -

Note that if you don't export HELLO from the package A, you will need to
use A::HELLO to get the internal symbol.  This is intended to look ugly to
remind you you're violating abstractions.

- - - - 

Does this help?  If it leaves you with more questions, feel free to ask
them.
From: Georges KO
Subject: Re: Some explanations on packages and symbols needed
Date: 
Message-ID: <m31yvw42uv.fsf@symbiose.gko.net>
Kent M Pitman <······@world.std.com> wrote: 

> the normal thing is to pass a keyword, since keywords self-quote and
> are convenient to type. 

    I should have thought about this...

> > 2) (it should be related to 1) if I do a (fboundp arg), I get also
> >nil... (the fonction exists).
> 
> (fboundp 'a:hello)

    The fboundp call takes places in the A package, but I guess it
didn't work because it "received" 'b:hello.

> Does this help?  If it leaves you with more questions, feel free to
> ask them.

    Yes, thank you.
-- 
 Georges KO (Taipei, Taiwan)                                      ···@gko.net
                                                       Mardi 28 novembre 2000
From: Kent M Pitman
Subject: Re: Some explanations on packages and symbols needed
Date: 
Message-ID: <sfw66l8w120.fsf@world.std.com>
Georges KO <···@gko.net> writes:

> Kent M Pitman <······@world.std.com> wrote: 
> 
> > the normal thing is to pass a keyword, since keywords self-quote and
> > are convenient to type. 
> 
>     I should have thought about this...
> 
> > > 2) (it should be related to 1) if I do a (fboundp arg), I get also
> > >nil... (the fonction exists).
> > 
> > (fboundp 'a:hello)
> 
>     The fboundp call takes places in the A package, but I guess it
> didn't work because it "received" 'b:hello.

No.  To the extent the call "takes place" in any package, it takes place in
the package that is the binding of *PACKAGE*.  What's important about this is
that if you do:

 (IN-PACKAGE "B")
 (DEFUN FOO () (FBOUNDP 'A:FOO))
 (IN-PACKAGE "C")
 (DEFUN FOO (PACKAGE-NAME)
   (LET ((*PACKAGE* (FIND-PACKAGE PACKAGE-NAME)))
     (B:FOO)))
 (IN-PACKAGE "D")
 (C:FOO "E")

the "call" to FBOUNDP will be in package "E" (which I'm assuming exists)
in the sense that any operation which cares about the "current package" will
see *PACKAGE* being #<PACKAGE "E">.  But, in fact, nothing in the call chain
from C:FOO all the way down to the FBOUNDP does in fact care what the package
is since nothing is doing other than manipulate already-interned symbols.
So this codes is insensitive to the prevailing binding of *PACKAGE* and the
attempt to bind *PACKAGE* around the call to B:FOO is pointless.

The way to say what you wanted to say is to talk about what package was
current at the time the form was read, not at the time of execution, since
it's the read-time value of *PACKAGE* that matters, not the execution-time
value, unless you're dynamically calling INTERN.  Normally INTERN is called
by READ, which is why read-time matters.  And a specific reference to A:FOO
or A::FOO causes the INTERN done at read-time to select a different symbol
than the "FOO" in *PACKAGE* at readtime.

The really critical thing to understand is that Lisp "code" is NOT text.
Program text must be processed through READ in order to create objects 
which are the "code".  For example, I can do

 (LIST (INTERN "FBOUNDP" "A") (INTERN "FBOUNDP" "B"))

and get a piece of Lisp program that is not and never has been text, and
there would be no semantics to this code if Lisp semantics were defined
in terms of text.  Because Lisp semantics are defined in terms of the list
structure itself (that is, a compund form is a list, the operator in the
form is the car of that list, etc.), there is a meaning to this.  And that
meaning does not depend on reader variables.  It depends on the packages
which might have been chosen by reader variables if this had gone through
read but instead was chosen explicitly by another program because we did
not go through read.

Sorry to be so pedantic here on such a small point of terminology but I want
to make sure you're getting a good mdoel.  I hope these extra examples avoid
any possible confusion on this.