I’ve only had a glance at what you wrote because it’s mostly stuff that seems obviously right to me.
I’d like to see the more common software engineering terminology used here though because this is effectively interfaces/typeclasses/traits. You define the desired features in the interface, all implementations must provide implementations for those features and this is verified automatically.
I have not looked too closely at the detailed implementation yet because I think there’s still a major issue to resolve at a more abstract level: How to handle differences between mostly similar implementations?
I think this issue is also what @nbp alluded to.
While most of the functionality can (and IMHO should) be abstracted between “equivalent” implementations, the reason there even are multiple implementations of ostensibly the same thing is that they implement some details differently and, while mostly the same, still have different sets of features.
It’s these implementation-specific features I’m concerned with because they’re sometimes indispensable. It may very well be the case that my service depends on some specific feature that only a subset of all implementers of the generic interface offer and that must be a legal case in this abstraction system.
It must therefore be possible to have optional parts of the interface. These would ideally be abstracted to some degree as to not be entirely implementation-specific. Services would then need to explicitly request the features and there should be at least one implementation. Using the service with an implementation that does not implement the required feature should result in an eval error that ideally lists all alternative implementations which do implement the requested feature.
Given that interfaces are treated as types in most languages I know of, it probably makes sense to implement them as module system types too.
Since a mechanism for optional features would be required anyways, you could perhaps even build the entire interface definition out of optional features because they all need to be verified anyways and this could allow some niche implementations for some use-cases that don’t implement all the features that the abstract interface for its kind of service usually assumes.
I also see this RFC to be a precursor for non-systemd service manager support which is in turn required for NixOS on non-Linux kernels.
It’s much the same issue: systemd and other service managers implement the same core feature set (define services, how to run them and dependencies between services) but have significant differences in how that’s implemented and what additional options you can declare. As I’ve written before in RFC 163, I think it wouldn’t be acceptable to dumb down our service definition interface to the lowest common denominator, especially when the alternative options are, frankly, obviously technologically inferior.
With a service manager interface with optional features, it’d be possible to incrementally introduce alternative service managers without causing unreasonable maintenance overhead for module maintainers or any downsides for systemd users.