Re: clos mop
"Tim Bradshaw (as tfb at cley dot com)" <[email protected]>
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
Disclaimer: my view of what program design should be like is I suspect now extremely divergent from what a lot of latter-day CL people do. I don't want to argue about this: they can go their way, I will go mine.
If I design a system which, say, wants to provide a definition for SLOT-VALUE, I could do it like this:
(defpackage :splod
(:use :cl)
(:shadow #:slot-value)
(:export #:slot-value))
(in-package :splod)
(defun slot-value (o s)
...
(cl:slot-value o s)
...)
So, OK. Now *every client of this package* has to say
(defpackage :package-using-splod
(:use :cl)
(:shadowing-import-from :splod #:slot-value))
or, if splod provides other symbols which don't clash with CL but should be used:
(defpackage :package-using-splod
(:use :cl)
(:use :splod)
(:shadowing-import-from :splod #:slot-value))
In other words *every client needs to know things about the implementation of splod*.
If, later, you decide that splod also needs to export WITH-SLOTS, then *you break every package that uses it*, because every package using it has to know things about its guts. You've made life momentarily easier for yourself at the cost of hurting every user.
Instead, you do this:
(defpackage :cl/splod
... huge long definition which imports every symbol from CL except
SLOT-VALUE and then rexports those symbols ...
(:export #:slot-value))
Now the cl/splod package is a package which is like CL, except that slot-value is not CL's slot-value.
Client packages now just say:
(defpackage :package-using-splod
(:use :cl/splod))
And when cl/splod changes so that it also replaces with-slots, no client needs to care.
Well, it's a pain writing the package definition for cl/splod, until you have a macro (but even then, that's OK: it places the burden on the package providing the functionality not the many consumers). But conduit packages provides a macro whose purpose is to support just this sort of thing. UIOP also now provides something similar but somewhat harder to use as far as I can tell.
So using conduit packages you'd write:
(define-package :cl/splod
(:extends/excluding :cl
#:slot-value)
(:export #:slot-value))
Although I generally think it's much cleaner if conduits are pure, with no implementation in them, so splod might now look like:
(define-package :cl/splod
(:use)
(:extends/excluding :cl
#:slot-value)
(:export #:slot-value))
(define-package :splod/impl
(:use :cl/splod))
(in-package :splod/impl)
(defun slot-value ...)
There is (fairly recently) a define-conduit-package macro which ensures that conduits are pure.
All of these expand to DEFPACKAGE, so you can use any options that your DEFPACKAGE has. Their specific options are extends (just reexport everything) extends/excluding (reexport everything but ...) and extends/including (reexport only ...).
It's arguable that shadow / shadowing-import is useful when you're writing something which is never going to provide functionality to anything else. But then, once you *have* conduits, you can just use a conduit anyway.
I find it hard to think of other uses of it which don't just indicate misdesign. As best I can tell (and certainly from memory of CL in the late 80s) I think people didn't really understand how the package system could be used at first. I'd argue that a lot of people still don't (witness the colon plague in so much recent code), but see the disclaimer at the top.
--tim
> On 1 Apr 2025, at 15:29, David McClain <[email protected]> wrote:
>
> Hi Tim,
>
> I’d like to understand your objections to “shadowing”? I suspect there is something very important to learn from you.
>
> - DM
>
>> On Apr 1, 2025, at 02:42, Tim Bradshaw (as tfb at cley dot com) <[email protected]> wrote:
>>
>> On 31 Mar 2025, at 18:24, Paul Werkowski (as pw at snoopy dot qozzy dot com) <[email protected]> wrote:
>>>
>>>
>>>
>>> SBCL was very unhappy with me messing with shadowing its slot-value warning loudly about violating PACKAGE-LOCK protocols.
>>
>> That was correct. You're not allowed to do that, see https://www.lispworks.com/documentation/HyperSpec/Body/11_abab.htm. Given LW does special magic for slot-value that might not work for LW either. It'a the same as, say, locally binding car as a function.
>>
>> If you want a system which is like CL but slot-value has different behaviour, then the answer is a conduit: a package which reexports all the symbols in CL, except slot-value, and provides its own version of that. Someone once wrote a variant defpackage to make defining conduits easy...
>>
>> (Please, no-one suggest shadow / shadowing-import. Just ... don't).
>>
>> --tim
>
>
_______________________________________________
Lisp Hug - the mailing list for LispWorks users
[email protected]
http://www.lispworks.com/support/lisp-hug.html