Hello all!
I'm experiencing some problems using packages in Lisp and I'm wondering
what your opinions are about the packages-facility in Lisp. I've been
hearing around and most of my comrades suggest not to use packages. I'd
like to use them to avoid nasty things like name-clashes (that's what
they're for, right?). Is there any guide on how packages should be used?
Description of the problem I ran into:
Let's say I have some package :exporting-package, which has two
functions: ep-internal-fn and ep-external-fn. The ep-internal-fn gets a
string as argument and returns a symbol using (read-line str NIL NIL).
The ep-external-fn uses eq to compare the result of ep-internal-fn with
a pre-programmed symbol 'TEST. The ep-external-fn is exported.
Now another package is defined :importing-package which uses the
:exporting-package (use-package). When ep-external-fn is called, the
equality is always false. This happens because the result of
ep-external-fn is a symbol in the package :importing-package, whereas
the 'TEST symbol is defined in the :exporting-package.
Many thanks in advance,
Joris Bleys
Joris Bleys wrote:
> Hello all!
>
> I'm experiencing some problems using packages in Lisp and I'm wondering
> what your opinions are about the packages-facility in Lisp. I've been
> hearing around and most of my comrades suggest not to use packages. I'd
> like to use them to avoid nasty things like name-clashes (that's what
> they're for, right?). Is there any guide on how packages should be used?
No, you absolutely should use packages. Programming in the CL-USER
package means your code cannot be integrated with others who do the
same, and is possibly nonportable anyway since implementations can
stick any symbols they want in that package.
I typically make the packages fairly large, and put their definitions
off in their own files, but this is style.
It's a good idea to avoid using the :: package prefixes when possible.
That's a sign that someone is cheating and going behind the back
of a package's public interface.
> Let's say I have some package :exporting-package, which has two
> functions: ep-internal-fn and ep-external-fn. The ep-internal-fn gets a
> string as argument and returns a symbol using (read-line str NIL NIL).
> The ep-external-fn uses eq to compare the result of ep-internal-fn with
> a pre-programmed symbol 'TEST. The ep-external-fn is exported.
>
> Now another package is defined :importing-package which uses the
> :exporting-package (use-package). When ep-external-fn is called, the
> equality is always false. This happens because the result of
> ep-external-fn is a symbol in the package :importing-package, whereas
> the 'TEST symbol is defined in the :exporting-package.
That symbol was part of the API of the exported function, so it itself
should have been exported also. Or, you could have used a keyword
symbol.
(Also be careful when calling READ-LINE that you've bound *PACKAGE*
appropriately.)
Paul
On 2005-05-30 14:23:50 +0200, "Paul F. Dietz" <·····@dls.net> said:
>> I'd like to use them to avoid nasty things like name-clashes (that's
>> what they're for, right?).
>
> No, you absolutely should use packages.
Ok, so we tend to agree :).
>
>> Let's say I have some package :exporting-package, which has two
>> functions: ep-internal-fn and ep-external-fn. The ep-internal-fn gets a
>> string as argument and returns a symbol using (read-line str NIL NIL).
>> The ep-external-fn uses eq to compare the result of ep-internal-fn with
>> a pre-programmed symbol 'TEST. The ep-external-fn is exported.
>>
>> Now another package is defined :importing-package which uses the
>> :exporting-package (use-package). When ep-external-fn is called, the
>> equality is always false. This happens because the result of
>> ep-external-fn is a symbol in the package :importing-package, whereas
>> the 'TEST symbol is defined in the :exporting-package.
>
> That symbol was part of the API of the exported function, so it itself
> should have been exported also. Or, you could have used a keyword
> symbol.
Maybe, I was a bit unclear with my problem statement. The symbol is not
part of the API and should remain unvisible for the users of
:exporting-package. So I guess what I want to do is to make sure that
the result of the call to the read-line fn returns a symbol inside the
:exported-package, but I don't know how to do so. Both ep-internal-fn
and ep-external-fn are defined in the package :exporting-package (using
in-package).
> Paul
Thanks for your support!
Joris
Joris Bleys wrote:
> So I guess what I want to do is to make sure that
> the result of the call to the read-line fn returns a symbol inside the
> :exported-package, but I don't know how to do so. Both ep-internal-fn
> and ep-external-fn are defined in the package :exporting-package (using
> in-package).
Ah! The reader will intern symbols in the package
indicated by the special variable *PACKAGE*. At runtime, this
could be anything (not necessarily either of your two packages).
To control that, bind *PACKAGE* around the READ-LINE call:
(let ((*package* <desired-package>))
(read-line str nil nil))
Paul
On 2005-05-30 15:04:25 +0200, "Paul F. Dietz" <·····@dls.net> said:
> Ah! The reader will intern symbols in the package
> indicated by the special variable *PACKAGE*. At runtime, this
> could be anything (not necessarily either of your two packages).
Ok, thanks for your reply!
Joris
Joris Bleys <······@arti.vub.ac.be> writes:
> On 2005-05-30 14:23:50 +0200, "Paul F. Dietz" <·····@dls.net> said:
>
>>> I'd like to use them to avoid nasty things like name-clashes
>>> (that's what they're for, right?).
>> No, you absolutely should use packages.
>
> Ok, so we tend to agree :).
>
>>
>>> Let's say I have some package :exporting-package, which has two
>>> functions: ep-internal-fn and ep-external-fn. The ep-internal-fn
>>> gets a string as argument and returns a symbol using (read-line str
>>> NIL NIL). The ep-external-fn uses eq to compare the result of
>>> ep-internal-fn with a pre-programmed symbol 'TEST. The
>>> ep-external-fn is exported.
>>> Now another package is defined :importing-package which uses the
>>> :exporting-package (use-package). When ep-external-fn is called,
>>> the equality is always false. This happens because the result of
>>> ep-external-fn is a symbol in the package :importing-package,
>>> whereas the 'TEST symbol is defined in the :exporting-package.
>> That symbol was part of the API of the exported function, so it
>> itself
>> should have been exported also. Or, you could have used a keyword
>> symbol.
>
> Maybe, I was a bit unclear with my problem statement. The symbol is
> not part of the API and should remain unvisible for the users of
> :exporting-package. So I guess what I want to do is to make sure that
> the result of the call to the read-line fn returns a symbol inside the
> :exported-package, but I don't know how to do so. Both ep-internal-fn
> and ep-external-fn are defined in the package :exporting-package
> (using in-package).
For starters, presumably you're using READ not READ-LINE as the latter
returns a string, not a symbol. Or you're using READ-LINE and then
INTERN to create a symbol, which is arguably a better plan that using
READ so you don't have to worry about READ reading some other kind of
object. At any rate, the problem you're having is that READ and INTERN
both use the runtime value of *PACKAGE* to determine how to
find/intern symbols. So it doesn't matter that ep-internal-fn happens
to be defined in a file that is read with a particular *PACKAGE*--what
matters is what *PACKAGE* is when it is called. However you can fix
this easily enough:
(defun ep-internal-fn (stream)
(let ((*package* (find-package :the-package-you-want)))
(read in nil nil)))
or
(defun ep-internal-fn (stream)
(let ((string (read-line in nil nil)))
(when string
(intern string :the-package-you-want))))
Note, in the later version you'll probably want to use (string-upcase
string) as the argument to INTERN in order to match the reader's
default upcasing of symbol names, i.e.
(defun ep-internal-fn (stream)
(let ((string (read-line in nil nil)))
(when string
(intern (string-upcase string) :the-package-you-want))))
-Peter
--
Peter Seibel ·····@gigamonkeys.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
Hi Peter,
> For starters, presumably you're using READ not READ-LINE as the latter
> returns a string, not a symbol. Or you're using READ-LINE and then
> INTERN to create a symbol, which is arguably a better plan that using
> READ so you don't have to worry about READ reading some other kind of
> object.
Actually I'm using (read-from-string "COMMAND extra stuff which ain't
important" NIL NIL) which returns COMMAND as a symbol. I initially
mispelled this as I thought this was not of major influence on my
problem at hand).
> At any rate, the problem you're having is that READ and INTERN
> both use the runtime value of *PACKAGE* to determine how to
> find/intern symbols. So it doesn't matter that ep-internal-fn happens
> to be defined in a file that is read with a particular *PACKAGE*--what
> matters is what *PACKAGE* is when it is called.
Ok, I agree to you this indeed is the problem and the solution. I just
find it a bit difficult for a programmer to make sure symbols are
created in the right package. I wonder when calling an internal
function, the *package* is not automatically changed to the package to
the one in which it was defined.
Thanks for your help!
Joris
Joris Bleys <······@arti.vub.ac.be> writes:
> Hi Peter,
>
>> For starters, presumably you're using READ not READ-LINE as the latter
>> returns a string, not a symbol. Or you're using READ-LINE and then
>> INTERN to create a symbol, which is arguably a better plan that using
>> READ so you don't have to worry about READ reading some other kind of
>> object.
>
> Actually I'm using (read-from-string "COMMAND extra stuff which ain't
> important" NIL NIL) which returns COMMAND as a symbol. I initially
> mispelled this as I thought this was not of major influence on my
> problem at hand).
>
>> At any rate, the problem you're having is that READ and INTERN
>> both use the runtime value of *PACKAGE* to determine how to
>> find/intern symbols. So it doesn't matter that ep-internal-fn happens
>> to be defined in a file that is read with a particular *PACKAGE*--what
>> matters is what *PACKAGE* is when it is called.
>
> Ok, I agree to you this indeed is the problem and the solution. I just
> find it a bit difficult for a programmer to make sure symbols are
> created in the right package. I wonder when calling an internal
> function, the *package* is not automatically changed to the package to
> the one in which it was defined.
So one nit-picky, but actually quite important point, is that's it
doesn't really make sense to talk of the package in which a function
was defined. For instance, in what package is this function defined:
(in-package :foo)
(defun bar::baz () 'hello)
The value of *PACKAGE* when this file is read will be the package
"FOO" but the name of the function BAZ will not be interned in
"FOO"[1]. So, in your dream Lisp, should *PACKAGE* be bound to the
package "FOO" or the package "BAR" when BAZ is called? That's a
rhetorical question--I'm sure you could come up with an answer and
maybe even make a case for why it makes more sense than the other
answer. But the fact of the matter is, that functions aren't "in"
packages--just their names. It's worth getting this straight in your
head because once you realize that packages are *just* a scheme for
managing names, and only indirectly the things they name, the package
system will make a lot more sense.
-Peter
[1] Well it could, if the "FOO" and "BAR" packages had the appropriate
relationships established. But leave that aside for the moment.
P.S. If you really want to define packages that rebind *PACKAGE* at
runtime to the package that was current when the function was defined,
you could define this macro:
(defmacro defun/package (name (&rest args) &body body)
`(defun ,name ,args
(let ((*package* ,*package*))
,@body)))
And if you want functions that bind *PACKAGE* to the HOME package of
the name of the function, you could define this one:
(defmacro defun/package (name (&rest args) &body body)
`(defun ,name ,args
(let ((*package* ,(symbol-package name)))
,@body)))
I'm not sure that either of these are particularly useful--it's
probably better to be explicit about what package you are using at
runtime to lookup/intern names.
--
Peter Seibel ·····@gigamonkeys.com
Lisp is the red pill. -- John Fraser, comp.lang.lisp
Hi Peter,
> It's worth getting this straight in your
> head because once you realize that packages are *just* a scheme for
> managing names, and only indirectly the things they name, the package
> system will make a lot more sense.
Thanks for you excellent guidance, I realized it was just about names
but did not realise all the implications it has to write descent Lisp
code. With your help it all makes a bit more sense now.
Thanks again!
Joris
Joris Bleys wrote:
> Maybe, I was a bit unclear with my problem statement. The symbol is not
> part of the API and should remain unvisible for the users of
> :exporting-package. So I guess what I want to do is to make sure that
> the result of the call to the read-line fn returns a symbol inside the
> :exported-package, but I don't know how to do so. Both ep-internal-fn
> and ep-external-fn are defined in the package :exporting-package (using
> in-package).
Maybe you want (intern string :exporting-package) instead of read-line?
But indeed this sounds like a strange attempt. It sounds as if you
wanted to use packages just to get more efficient string comparisons.
Wouldn't a hashtable be good enough for such a purpose?
If you rely on "TEST" giving you some specialized behavior, that would
indeed be part of your interface...
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
Pascal Costanza wrote:
> Joris Bleys wrote:
>
>> Maybe, I was a bit unclear with my problem statement. The symbol is
>> not part of the API and should remain unvisible for the users of
>> :exporting-package. So I guess what I want to do is to make sure that
>> the result of the call to the read-line fn returns a symbol inside the
>> :exported-package, but I don't know how to do so. Both ep-internal-fn
>> and ep-external-fn are defined in the package :exporting-package
>> (using in-package).
>
> Maybe you want (intern string :exporting-package) instead of read-line?
That was a brain fart. Sorry. ;)
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
Hi Pascal,
Don't I know you from somewhere? ;)
>> Maybe, I was a bit unclear with my problem statement. The symbol is not
>> part of the API and should remain unvisible for the users of
>> :exporting-package. So I guess what I want to do is to make sure that
>> the result of the call to the read-line fn returns a symbol inside the
>> :exported-package, but I don't know how to do so. Both ep-internal-fn
>> and ep-external-fn are defined in the package :exporting-package (using
>> in-package).
Ok, I tried to abstract my problem a bit, trying to make the problem as
clear as possible, but my attempt ended in a disaster :).
The :exporting-package really is a client. This client uses simple
crlf-ended lines over a tcp-connection. Now for extracting the commands
they receive, the first word of this line always resembles the command
sended and is implemented in ep-internal-fn (the real name is
reply->command. It is actually implemented as a (read-from-string reply
nil nil).
The ep-external-fn is of a higher-level like 'start-client' and checks
the incoming commands from the server are eq to the expected command.
So the comparisons are used inside the ep-external-fn and should not be
visible to the user of the :exporting-package.
> Maybe you want (intern string :exporting-package) instead of read-line?
This might indeed be the function I'm looking for. It seems more
elegant than setting *package* by hand. Oops, just read your reply :p,
so I might look very stupid now :). But I indeed want to make the
read-from-string result internal. Problem is, that has got no name, as
it is just past as the return value of a function straight in the
eq-test.
However, doing so requires the programmer to be realy careful when
employing packages. I'd like to think that calling internal functions
should automagically change the *package* to the package it was
internal in, but I guess there are good reasons, which I don't yet
fully (and might never :)) understand, for not doing so.
> But indeed this sounds like a strange attempt. It sounds as if you
> wanted to use packages just to get more efficient string comparisons.
> Wouldn't a hashtable be good enough for such a purpose?
This package is actually used to get to a higher level of commands and
thus does more than a simple string comparisons. Hashtables are a good
idea, but the protocol used is very straight forward and this might
result in overkill, at least in the client.
Thanks for your advice and the time for writing it down!
Joris
Joris Bleys wrote:
> Hi Pascal,
>
> Don't I know you from somewhere? ;)
That must be a coincidence. ;)
>> Maybe you want (intern string :exporting-package) instead of read-line?
>
> This might indeed be the function I'm looking for. It seems more elegant
> than setting *package* by hand. Oops, just read your reply :p, so I
> might look very stupid now :).
Maybe we both do. ;)
> However, doing so requires the programmer to be realy careful when
> employing packages. I'd like to think that calling internal functions
> should automagically change the *package* to the package it was internal
> in, but I guess there are good reasons, which I don't yet fully (and
> might never :)) understand, for not doing so.
It's not that hard to understand. You have to get two things straight:
- When the Lisp reader reads in your source code (the original source
code, not what you want to do at runtime), it uses *package* to
determine the package of the symbols that are part of your source code.
That's the sole purpose of *package*. You can reuse that functionality
for your own stuff at runtime, but you have to imitate that behavior (so
bind *package* correctly, or use INTERN with a second parameter
appropriately). Read time and runtime are just two different times for a
Lisp program, and you just have to keep them separated in your head.
- It might have been possible to automagically rebind *package*,
whenever a function is called, to the home package of the symbol whose
symbol-function is that function at runtime. This would incur a serious
overhead though, and you would have to care about obvious and not so
obvious corner cases. For example, what happens when you call an
anonymous function? What if you change the fdefinition of a function at
runtime? etc.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
In article <··························@artivubacbe>,
Joris Bleys <······@arti.vub.ac.be> wrote:
> However, doing so requires the programmer to be realy careful when
> employing packages. I'd like to think that calling internal functions
> should automagically change the *package* to the package it was
> internal in, but I guess there are good reasons, which I don't yet
> fully (and might never :)) understand, for not doing so.
There are. Most importantly, how would you avoid such behavior when you
don't want it? (declare (do-not-automatically-frob-*package*
function-name))? If *package* always changes to the home package of the
called function, it's impossible to implement READ and friends. This
would definitely bug Lisp implementors, who usually implement READ in
Lisp.
-bcd
--
*** Brian Downing <bdowning at lavos dot net>
Joris Bleys <······@vub.ac.be> writes:
> name-clashes (that's what they're for, right?). Is there any guide on
> how packages should be used?
Have you checked the chapter on packages:
21. Programming in the Large: Packages and Symbols
http://www.gigamonkeys.com/book/programming-in-the-large-packages-and-symbols.html
in Peter Seibel's book?
Practical Common Lisp
http://www.gigamonkeys.com/book/
Paolo
--
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (see also http://clrfi.alu.org):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface