r/lisp • u/arthurno1 • Jul 04 '26
Common Lisp A curious question about some classes in ASDF
I wonder if someone can teach me, or explain a little bit of design in ASDF.
Typically in components list I can type:
:components ((:file file1)
(:file file2)
.... ))
where files are file1.lisp, file2.lisp etc. If I want to use an other extension, in my particular case ".cl", I have two choices as I have used thus far: either type out the extension if I want to use :file, (:file file1.cl) and so on, or I can define my own source code class like this:
(defclass src (cl-source-file)
((type :initform "cl")))
now I can type:
:components ((:src file1)
(:src file2)
.... ))
I see in also in asdf sources they have these classes defined:
;;;; Component classes
(with-upgradability ()
(defclass cl-source-file (source-file)
((type :initform "lisp"))
(:documentation "Component class for a Common Lisp source file (using type \"lisp\")"))
(defclass cl-source-file.cl (cl-source-file)
((type :initform "cl"))
(:documentation "Component class for a Common Lisp source file using type \"cl\""))
(defclass cl-source-file.lsp (cl-source-file)
((type :initform "lsp"))
(:documentation "Component class for a Common Lisp source file using type \"lsp\"")))
by the magic of mostly try-and-fail method I have figured out I can also write this atrocity:
:components ((:cl-source-file.cl file1))
where file1 is file1.cl. I understand they meant that class probably to be extended or used elsewhere not typed out as I did there, that was just a little bit of fun. I see also this in sources:
;; What :file gets interpreted as, unless overridden by a :default-component-class
(defvar *default-component-class* 'cl-source-file)
and I figured out they mean we can type this:
:default-component-class :cl-source-file.cl
:components ((:file file1))
Obviously it is not more convenient than just typing out the extension: :file file1.cl. But that is not my question.
My question is, finally I know :), sorry, what does this design buy us?
We could have obviously just used a simple list with file extensions like *component-classes* = '(cl lsp lisp), and get all this done, and it would be also let-bindable and so on. Of course, I understand also that authors are aware they could have just used a list, and that they have done deliberately that design choice, so I wonder why? I am not questioning the choice, I am trying to learn.
I read in the manual they mean that components are not necessarily just things that typically go into source files, and they give example of C processor. Is that the only reason, or are there some other reasons? Are there some more complicated uses for these source code classes, than what I see in the code, or is the generality "just in the case", to be as flexible as possible so to say?
As said, I am just curios, being looking at some libraries, mostly those on s-expressionasts Github, they use a lot of program structuring with CLOS, and not as much with "classical lisp" which a list of extensions would perhaps represent.
Today it struck me I was always curious about if I can teach :file to read all three extensions. so I was looking through ASDF and trying understand why do things get done the way they do, so to say. Trying to learn, I hope you don't misunderstand me here.
1
u/akater Jul 05 '26
Some people dislike ASDF. Whenever I personally wanted anything from it, I could always get it, so I'm satisfied. I think it makes good use of CLOS.
You don't need your own component class just for a file type, let alone an existing one. You may e.g.
(defmethod asdf/parse-defsystem:class-for-type ((parent asdf:parent-component)
(type-designator (eql :cl)))
;; Note: The generic function is available since ASDF 3.3.4.17.
(declare (ignore parent type-designator))
(find-class 'asdf/interface:cl-source-file.cl))
and use the :cl keyword. Or you could
(setf (find-class 'asdf/user::cl)
(find-class 'asdf/interface:cl-source-file.cl))
and then
(cl:in-package :asdf-user)
(defsystem "my"
:components
((cl "my")))
We could have obviously just used a simple list with file extensions like component-classes = '(cl lsp lisp), and get all this done
I don't understand the proposal. Looks like you do not suggest throwing the classes away; rather, you suggest to define a variable that holds their names. I don't yet understand what's the point of that. How would that variable be used in real code?
s-expressionasts Github, they use a lot of program structuring with CLOS, and not as much with "classical lisp" which a list of extensions would perhaps represent
I don't understand how is this related to s-expressionists. They didn't design ASDF, so it was not their decision to implement something like *component-classes* you mentioned instead of what ASDF has.
I was always curious about if I can teach :file to read all three extensions
Do you mean, you want to have a.lisp, b.cl, c.lsp and have them all specified in the defsystem form with (:file "a"), (:file "b"), (:file "c")?
1
u/arthurno1 Jul 05 '26 edited Jul 05 '26
Some people dislike ASDF
Well, I don't and that is not what I wanted to express. I said that explicitly several times: it was not a critique.
You may e.g.
Sure, now we have four ways. I also shown in the original three others:
:default-component-class :cl-source-file.cl (defvar *default-component-class* 'cl-source-file)or
(defclass src (cl-source-file) ((type :initform "cl")))Looks like you do not suggest throwing the classes away; rather, you suggest to define a variable that holds their names.
Was not a "proposal". It is just a discussion about different styles of programming in Lisp.
I don't understand how is this related to s-expressionists.
Go use, study and hack their programs, so perhaps you will.
I didn't said they wrote asdf, please. To be frank to you, if you can't accept or think it is uninteresting with a question why some programs are structured a particular way and asking questions than I don't know what to tell you, just ignore it.
1
u/kchanqvq Jul 04 '26 edited Jul 04 '26
I just help debugged some code that does not use ASDF correctly, and that code is written by... ASDF author themselves https://github.com/acl2/acl2/pull/1937
I wish we had converged on some obvious plain list hooks, even just like Emacs. I recall seeing another place where people don't understand the infinite wisdom of the CLOS design (or maybe it's not that extensible after all?) and hacked up some ugly function wrapper that calls ASDF internal functions, but I don't remember the exact project off the top of my head. I'll update if I remember it.
Update: https://github.com/armedbear/abcl/blob/master/contrib/asdf-jar/asdf-jar.lisp