@jakehamilton
So, Iām not nearly done, at lot of it looks fantastic and Iām really impressed. In terms of criticism one of the first things I run into is āwhere is lib defined?ā. For example
- first I went to src/staging/stage0
- then that lead me to builders
- not sure what
kaem
is, so I went to one of the other builders
- got to
lib.modules.override.default
but I donāt know that behavior and I donāt/canāt know where that is defined, because lib is an argument and we (generally) donāt know everywhere this function is called
Which is a bigger design principle I think we should discuss.
_
When we read lib.doSomething
I think we pretty much all expect it do the same thing every time. But lib.modules.override.default
could return null every time for all we know; it is an argument after all. Instead of importing lib (like most languages), when we have it as an untyped argument we loose all ability to locally/statically reason about the code. As a reader, we canāt even assume lib.modules.override.default
will be a function.
Readbility is one thing, but more importantly it makes code really really hard to refactor/maintain because, for example, if there is a null check on lib.modules.override.default
then we canāt really ever remove that null check, because maybe ā somewhere ā an argument does cause it to be null. āAnything is possible (thanks to arguments)ā might sound nice, but it does not help with understanding, debugging, and fully-testing code.
_
I know nix likes to be able to overwrite everything, that way (in theory) people donāt need to fork in order to modify. But after years of this approach, I think we can say it hasnāt really worked in practice. Perfect exampke is @ VlinkZ being unable to give an overlay of core stuff on nixpkgs because it breaks so many things. Even though heās plenty experienced in using Nix.
Its easier to fork and modify, than it is to surgically try to override/hack-in behavior. So I think, at least for foundation, its okay to loose that benefit. If someone wants to change foundational behavior, just fork.
_
The alternative, I think, is having lib as a subrepo or submodule (so that we can have a direct import of lib rather than lib as an argument). I know that goes against my original plan, but hey, thatās good. It means the prototypes are doing their job at changing my opinion/estimates. I now think a subrepo is the best way to make foundation maintainable and easy to reason about for new members, while still keeping lib
pure and isolated in its own repo.
I think we could avoid the need for subrepos if the builtin import
allowed for importing URLs. But thatāll be a topic for another time.