[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Subprojects in project.el (Was: Eglot, project.el, and python virtua
From: |
Dmitry Gutov |
Subject: |
Re: Subprojects in project.el (Was: Eglot, project.el, and python virtual environments) |
Date: |
Fri, 2 Dec 2022 03:32:42 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 |
Hi again,
It's probably time to continue here.
On 26/11/2022 09:26, Eli Zaretskii wrote:
Again, you are talking about project kinds already supported by project.el
as its built-ins. I'm asking how to produce a project of a custom type.
To produce a project of custom type, you decide the data structure for
that type, write implementations for all the required (and perhaps some
optional) generic methods, then create that structure.
It seems I need to spell out everything every time I'm writing something
because otherwise you interpret it out of context. So here: I'm asking how
to produce a customized project whose type is 'transient', but which doesn't
go by the rules of the built-in 'transient' project.
I'm trying to be precise both to avoid misunderstanding. Even here you
were using the terminology that seems to conflict with established practice.
IIUC, you want to produce a project whose type is not 'transient', but
which inherits from 'transient' some of its behaviors.
As for "project of custom type", where "custom" means "not one of the known
types", there's still a situation where my project is similar enough to one
of the built-in types to make reimplementation of all the APIs overkill.
One could want to use some of the APIs without change and customize others.
So this, too, is something that project.el should IMO allow without too much
fuss.
So, what you are asking for is perfectly reasonable in theory. Also the
current theory of OOP suggests that type inheritance comes with its
downsides as well. For instance, the straightforward way Joao was
suggesting (create a defclass) will mean nailing down the internal
structure of a type which would make it more difficult to create
internal changes to it -- because somebody might have inherited from it,
and might be using the exposed fields, etc.
Asking for a public constructor, however, can help in this regard as
well, if you understand how to implement delegation using it. Meaning,
you would still create your own type, but then to delegate the
implementations of methods you would create an instance of the type to
delegate to, and call said methods on it. This the type's evolution
would only be limited by the backward compatibility of its constructor.
You asked, however, how to instantiate a project of a type belonging to
"someone else". But didn't explain why.
The "why" is "because one needs to".
The question also sounded odd because there is little point to "inherit"
from 'transient'. Because that type's definition is only two lines:
(cl-defmethod project-root ((project (head transient)))
(cdr project))
There is literally nothing to reuse. The rest of that type's behaviors
reside in the default definitions of other generic functions. So you can
just create your own type, create its method for the above generic
function, and then override the rest of the behaviors as needed.
If you wanted to inherit from the 'VC-aware' backend, however, that is a
different discussion. I would ask which parts of it you need, and
whether you intend to honor the project-vc-* user options, as its
methods do. Or whether perhaps you just wanted to reuse the VC-based
fast file listing implementation. Which would be a little easier to make
public with an established signature.
The reasons not to rely on internal structure, as a reminder:
- The internal structures are prone to change, and you don't want your
code to break when that happens.
- When implementing some feature that works with projects, you generally
want it to work with all kinds of projects (which was the whole point of
project.el -- to make this approach work). And that would mean talking
to them through common methods, rather that examine the internals of
this or that project type.
I'm fine with all that, but it sounds like the above makes it impossible to
implement custom project objects, maybe because there's no make-project
method that one could use and/or subclass.
I usually answer this way because often it's not a good idea, and there
are better ways to reach the goals of the person who's asking.
Still, if you do want to inherit from 'VC-aware', we can make a public
constructor for it. Probably after Emacs 29 is released, and we can see
that the structure is settled (it's looking this way now).
As for 'transient', well, the constructor can be added as well. The
structure is stable and least likely to change; unless we just make an
executive decision to turn them all into structs or whatever. I just
didn't want to encourage people using it -- even Joao's usage is odd
because he not only calls the 'project-root' function, but also
'project-files', and it's just luck that its behavior suits his current
goals.