In large Lisp systems, it's easy to run into problems with the order in which files are loaded and compiled.
One often-vexing issue is where to put package declarations. If a file names an exported symbol such as foo:bar, the package foo with its export list must have been loaded earlier.
In general, it seems to me that in a big complicated system with lots of packages, it would be great if you could just first load all the files with defpackage forms, and get all those packages created and all the external variables externalized, and then load everything else.
However, in a situation I'm working on now, that doesn't work, because package X has (:import-from :y :a1 :a2), and the symbols :a1 and :a2 are not exported from :y. That is, X is exporting internal symbols of Y. This fails, because the symbols :a1 and :a2 do not exist, because they get created only when the files that define them get loaded. So doing all the package declarations first does not work.
Possible approaches:
(1) Too bad; you really do have to load the Lisp files that created those internal symbols after defining package X and before defining package Y.
(2) For Y to export symbols of X that X does not export, while being valid Common Lisp, is a bad practice.
It's a little hard to explain why we're doing this at all. I think it is historical. Originally there was only package X. Then it was considered a good idea to classify some of the functions in package X under a new package name, Y, to make the rest of the code clearer. Unfortunately, the symbols and functions and macros of package X may be too entangled to separate them out the way we would have done had the partition between X and Y been done from the beginning.
By "too hard" I mean that it's not worth the trouble to attain the goal, which was to remove a single ugly use of "::".
But I'm interested in the topic anyway.
-- Dan
Daniel Weinreb dlw@itasoftware.com writes:
However, in a situation I'm working on now, that doesn't work, because package X has (:import-from :y :a1 :a2), and the symbols :a1 and :a2 are not exported from :y. That is, X is exporting internal symbols of Y. This fails, because the symbols :a1 and :a2 do not exist, because they get created only when the files that define them get loaded. So doing all the package declarations first does not work.
You could add a (:intern :a1 :a2) clause to Y's defpackage form.
Zach
On 4/6/2011 1:12 PM, Daniel Weinreb wrote:
In large Lisp systems, it's easy to run into problems with the order in which files are loaded and compiled.
One often-vexing issue is where to put package declarations. If a file names an exported symbol such as foo:bar, the package foo with its export list must have been loaded earlier.
In general, it seems to me that in a big complicated system with lots of packages, it would be great if you could just first load all the files with defpackage forms, and get all those packages created and all the external variables externalized, and then load everything else.
However, in a situation I'm working on now, that doesn't work, because package X has (:import-from :y :a1 :a2), and the symbols :a1 and :a2 are not exported from :y. That is, X is exporting internal symbols of Y. This fails, because the symbols :a1 and :a2 do not exist, because they get created only when the files that define them get loaded. So doing all the package declarations first does not work.
Possible approaches:
(1) Too bad; you really do have to load the Lisp files that created those internal symbols after defining package X and before defining package Y.
(2) For Y to export symbols of X that X does not export, while being valid Common Lisp, is a bad practice.
It's a little hard to explain why we're doing this at all. I think it is historical. Originally there was only package X. Then it was considered a good idea to classify some of the functions in package X under a new package name, Y, to make the rest of the code clearer. Unfortunately, the symbols and functions and macros of package X may be too entangled to separate them out the way we would have done had the partition between X and Y been done from the beginning.
By "too hard" I mean that it's not worth the trouble to attain the goal, which was to remove a single ugly use of "::".
But I'm interested in the topic anyway.
As Einstein said, "Make everything as simple as possible, but no simpler." In this case, we begin from admittedly badly-factored code, so I do not find it interesting at all that the package system cannot unravel things for us. Indeed, with Einstein, I would be offended if it /did/ offer an elegant way out.
The only value I see in packages is in cases like this, in which the package system forces one to factor ones code correctly to make it happy. ie, The package system is an artificial and unwitting arbiter of clean code.
kt
On Wed, Apr 6, 2011 at 12:12 PM, Daniel Weinreb dlw@itasoftware.com wrote:
Possible approaches:
(1) Too bad; you really do have to load the Lisp files that created those internal symbols after defining package X and before defining package Y.
(2) For Y to export symbols of X that X does not export, while being valid Common Lisp, is a bad practice.
(3) (defpackage :x-and-y-need-refactored (:export :a1 :a2)), then (:use :x-and-y-need-refactored) in X and Y
(4) (defpackage :x (:import-from :y y::a1 y::a2)), assuming Y isn't locked on implementations that support that sort of thing
-b-