A programming language has a "core language" plus a package/module system.
In each successful language, the core language is neat-and-tidy,
but the package/module system is a Rube Goldberg machine.
See JavaScript/TypeScript, Python, or C/C++.
Lots of brain cycles are spent on "programming language theory".
We've roughly figured out the primitives required to express real-world computation.
In contrast, we apparently have no "package management theory".
We have not figured out the primitives required to express dependencies.
As a result, we keep building new variants and features,
until we end up with <script>, require(), import, npm, yarn, pnpm, (py)?(v|virtual|pip)?env, (ana)?conda, easy_install, eggs and wheels ...
Is it just a "law of software" that this must happen to any successful language?
Or are there examples of where this it has not happened, and what can we learn from them?
Is there a "theory of package management", or a "lambda calculus of package management" out there?
We have a good hunch. The basic theory behind Nix definitely goes in the right direction, and if we look away from all the surface-level nonsense going on in Nix, it's conceptually capable (e.g. [0]) of being a first-class language dependency manager.
For this to work at scale we'd need to overcome a couple of large problems though (in ascending order of complexity):
1. A better technical implementation of the model (working on it [1]).
2. A mindset shift to make people understand that "binary distribution" is not a goal, but a side-effect of a reasonable software addressing and caching model. Without this conceptual connection, everything is 10x harder (which is why e.g. Debian packaging is completely incomprehensible - their fundamental model is wrong).
3. A mindset shift to make people understand that their pet programming language is not actually a special snowflake. No matter what the size of your compilation units is, whether you call modules "modules", "classes" or "gorboodles", whether you allow odd features like mutually-recursive dependencies and build-time arbitrary code execution etc.: Your language fits into the same model as every other language. You don't have to NIH a package manager.
This last one is basically impossible at the current stage. Maybe somewhere down the line, if we manage to establish such a model successfully in a handful of languages and people see for themselves, but for now we have to just hold out.
[0]: https://code.tvl.fyi/about/nix/buildGo
[1]: https://cs.tvl.fyi/depot/-/tree/tvix/