This is true. I usually call what the OP calls 'program managers' 'distro package managers' and what the OP calls 'module managers' 'language-specific package managers'.

Neither pair of terms quite captures everything even though we do probably want a bipartite division here.

For example, Conda is (sort of) language-specific, being for Python, but it also tries to put together a coherent distribution. At the same time, it also includes multiple languages because it wants to include native dependencies, which usually means C and C++ code. Still, Conda is used for development environments and libraries, not necessarily for installing finished programs.

For another, Nix is firmly a distro-type package manager, even being used to power a whole Linux distribution. Nixpkgs forms a coherent collection, and only includes redundant versions of things as exceptional cases. But Nix doesn't have a global installation system; the 'global' namespace is in Nixpkgs, and it exists only at build time. Each thing you install with Nix is its own 'top-level entity', which the OP describes as characteristic of 'module managers'. But practical Nix use also further complicates things: Nixpkgs is a distro, but the Nix ecosystem also includes overlays that more resemble something like collections of 'modules', as well as tools for ingesting version data entirely from bona fide 'module managers' in a non-destructive way (i.e., you keep your Cargo.lock file or whatever but still just build with Nix) for various language-specific ecosystems.

As is usually the case with package management, we're looking at formations which, yes, cluster around technologiea with designs we can reasonably categorize, but are also substantially social or conventional. So sometimes it's useful to think not just of 'types of package managers' but 'types of packaging projects'. Without inventing better terms or thinking of a single hybrid concept that encapsulates both package managers and the packaging projects (collections and communities) associated with them, this gives us an obvious way to relate these exceptional cases to the straightforward ones: Conda and Nix are 'distribution/program manager tech' which has been further put to work for 'module management purposes' by their communities, in somewhat different ways.

Maybe there's an analogous case in reverse with npx in the Node world, where what was originally 'module management tech' has been adapted to managing executables that end users want to run, because previously using the 'naive' module management tech (npm) to do that could lead to weird and unnecessary collisions in the global install locations on the disk.

(There's also a bit of convergence there with Nix, since npx sort of vendorizes everything and also has you invoke it indirectly, as with `nix run`.

And since Nix is also a programming language, it's growing its own 'module management' tech, for now in the form of 'flakes', which is largely modeled on Rust's 'module management'.)

We might also identify a third type along these lines in something John Ericson (Ericson2314 here on HN and GH) in the Nix community has also advocated for a model we might call 'snippet extraction' for languages like Nix that are mostly glue code. Something like that is implemented in nix-thunk[1], which you can use to efficiently yank little bits of Nix out of large repositories of mostly non-Nix code. I've also seen something like it for shell snippets to be used in dotfiles[2]. Let's see if I can find that before the HN edit window closes on me. For now, these two tools both seem to pull code without specifying an interface for it (you decide how to use the code/files you pull in when you pull it), but we can also imagine a model that defines an interface for the bits you pull out, a kind of 'pseudo-module extraction' rather than 'snippet extraction'. If you use nix-thunk today to pull in a NixOS module or a flake or something, I guess that's what you're doing.

Anyway I think OP is a good place to start in thinking through how to divide up different package management traditions. Source-based vs. binary is probably the other essential one opposition to examine, along with its own exceptional/problematic cases and convergences.

—

1: https://github.com/obsidiansystems/nix-thunk

2: https://github.com/freshshell/fresh