emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: IDE


From: Lluís
Subject: Re: IDE
Date: Sat, 17 Oct 2015 19:18:41 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Dmitry Gutov writes:

> On 10/16/2015 07:47 PM, Lluís wrote:
>> * service-type: A type of service (one instance per type), like build, find 
>> root
>> directory, include search paths, compilation flags, etc.
>> 
>> * service: A specific implementation of a service type, like using vc-dir for
>> finding the root directory of a project.

> This sounds good. The implementations could be different (e.g. Java-ish 
> Service
> Locator [0]), but in the absence of other requirements the closest Emacs
> idiomatic structure would be a hook (list of functions) for each service
> type. Like project-find-functions, for example.

> Note that the objects the latter currently returns provide both "find root" 
> and
> "search path" services. Thus far it seemed to make sense. Can one, and would 
> one
> want to create different search-path services working with the same find-root
> service? That's an interesting question, and I'd love to see a practical
> example.

I didn't think of the "find path" functionality, but it does seem to make sense
to fold it into the "root path" service type.


> More generally, if a package P registers services A, B and C, if B needs some
> information from A, would we expect them to go through P-internal channels, or
> the public interface? For instance, most services might like to know the 
> project
> root (let's call that service type R).

> We could standardize the dependencies like that. In the simplest case, all
> services depend on project-root (except for itself), and we'll pass the 
> current
> project-root instance to each functions in their hooks. Then an element of
> service-b-functions will only return non-nil if that implementation of B can
> work with the given kind of project-root (or simply "project"; we might 
> include
> some more info into that instance as well).

> On the flip side, if there are no B implementations that can work with the
> currently detected R service r1, but there's a certain b2 in 
> service-b-functions
> that would work with r2 (currently shadowed by r1), we may be missing out.

Exactly. I started prototyping a few interfaces where all requests go through
the public interfaces. A project-type acts similarly to your "service locator"
link, and projects are simply a service locator that manage multiple
project-type instances grouped by the project.

More specifically, I was thinking about the following for deciding how to manage
results when information comes from different service implementations given a
service-type: for each public method of a service type, have a prioritized list
of method implementations, plus a property that tells us how to merge their
results. Possible properties would be returning the first non-error result from
the possible method instances or returning a concatenation of all non-error
results from all method instances.


>> * service-collection: A set of service implementations of the same service
>> type. This allows aggregating results from each service into a single answer.

> I suppose you can get this from the same service-b-functions hook, if you 
> treat
> it in a different way.

While prototyping it, I actually decided it makes sense to implement this
functionality on the service-type. It should know how to merge results from
multiple services, and every service must declare what service-type it provides.


>> * project-type: A type of project defines the service collections it provides
>> for each service type it knows about. An example could be an Emacs project
>> (knows how to auto-detect it, things like the build system it uses, etc.), 
>> and
>> Android project, a Linux kernel project, an autotools project, etc.

> Having to declare each combination of service-types that a project can provide
> still seems unnecessarily limiting (and tedious). But that's what 
> project-types
> would be for, right?

Exactly. My idea was that common project types would be written once declaring
all the service types they provide and through what service
implementations. In order to make projects easily customizable, there should
also be a project-type that can be dynamically constructed from some user
settings (some call in init.el or values on directory variables). Then you
simply overlay the custom project-type on top of some other project-type that is
auto-detected or specified by the user.


> How would a client even use those declarations? If we were to go that way, 
> it'd
> be better to simply have a project instance have a method that returns a list 
> of
> all services it supports. Or, even simpler, return a nil or raise a
> not-implemented error in each of the generic methods it doesn't implement.

I'm not sure I follow, but maybe I responded you on my previous paragraphs.


> Next, suppose a project instance can tell whether it provides a "build tool"
> service. What does a "call build task" command does? Looks for the current
> project and gives up if it doesn't provide the required service, or 
> specifically
> asks the locator for a project implementation that does provide that service?

I'd say both. My idea is that all project-types provide an auto-detection
function; given a path, tell me if it conforms to this project-type. Then, if we
do not know of any project instance for that path, build a new one that contains
instances of all project-types that match with it.


> In the latter case, we potentially buy more functionality, at the cost of 
> having
> different commands disagree about what the current project actually is.

> [0] http://martinfowler.com/articles/injection.html#ADynamicServiceLocator

Building a project from all matching project-types provides a clean solution to
this. But to be honest, I'm not sure if it makes much sense beyond taking a
single auto-detected project type plus an optional overlaid project-type that
contains user customizations.

For example, we could have a fallback "project-type-generic", a makefile-based
"project-type-make" and a very specific "project-type-linux". Should we overlay
all of them or just take the most "specific" one? (aka linux).

In the overlaying case, there should be a way to override decisions from other
project-types. This can get hairy, since in the beginning I said that each
per-service method implementation of a service-type method follows some property
(e.g., first match or concatenate), so now we want to override this. Should the
override be per method? Per service? At the entire project-type level?

In the second case, we can simply assign some priority number and take the
highest-priority project-type, and overlay the user-customizable project-type as
a special case.

I really am not sure about the project-type and project part.


Cheers,
  Lluis

-- 
"And it's much the same thing with knowledge, for whenever you learn
something new, the whole world becomes that much richer."
-- The Princess of Pure Reason, as told by Norton Juster in The Phantom
Tollbooth



reply via email to

[Prev in Thread] Current Thread [Next in Thread]