RFC: Introduce a crate-specific prelude in tor_chanmgr

Ian Jackson requested to merge Diziet/arti:prelude-rfc into main

Returning to Arti from the hackweek, I am motivated to fix something that is constantly in my way when working on our codebase: the ad-hoc maintenance of use lists at the top of each module.

This approach to namespace management is IMO very poor. Its downsides include:

  • Every time I call a new std function, or name a Tor type, I must add it to the imports. Then when I change my mind about where the call should be made, or whether it should be made at all, I must delete the import again.

  • I frequently experience merge conflicts when rebasing or reorganising branches, and occasionally when merging them.

  • Every module in our entire tree has a different namespace: names can mean different things, and be differently available, in different places.

I expect that some people are using systems like Rust-Analyser to automatically maintain these ad-hoc import lists. I do not allow automatic code-editing systems to edit my work that way. (And even if I wanted to, arranging to use something like Rust-Analyser at all is quite nontrivial given that I justifiably want to avoid trusting the Arti build system with all the privilege of my main account.)

So, for me, this is constant source of makework. It also tends to interrupt in the worst possible way - a distraction when reorganising my plans for some complex thing where I'm not sure what the best way is.

Ideally I would like the whole codebase to take following approach instead:

  1. Every crate will have a private module prelude.rs. It contains pub(crate) use and perhaps some trivial local type aliases or the like. It does not form part of the crate's API. Every module in the crate does use crate::prelude::*.

  2. We add #![allow(unused_imports)] to each prelude. The set of imports generally only ever grows.

  3. All imports that can be in prelude should be. Usually the exceptions are just private imports where there are nested visibility scopes (IMO not often a good practice, but sometimes justifiable).

This approach is not some strange thing I dreamt up myself. It's frequently done in the ecosystem and people have even written blog posts advocating it

Some contributors may find this approach annoying in the other direction: according to point 3 above the it will no longer be appropriate to apply compiler suggestions about imports, randomly adding imports to the various modules ad-hoc.

It might be possible to use some CI system to check for, but I don't think clippy supports this (ICBW), so it would have to be ad-hoc (and therefore have an ad-hoc way of dealing with the inevitable exceptions). And in any case I'm fairly sure diverting automatically-adeded use to a prelude is not possible, so this would be more work for those contributors who do things that way.

So if my proposal above is not suitable, I suggest the following compromise:

  1. Contributors are free to violate point 3 above, and put imports whereever they like.

  2. I volunteer to tidy this situation up, continually, as and when I encounter it.

Yes, really. Maintaining all the preludes personally will be less work than constantly fighting per-module imports. If necessary I can invent ad-hoc tooling. That I am proposing doing all this work myself will convey to you how much of my time I feel the current approach is costing.

Merge request reports