Stuttering #66
Replies: 21 comments 9 replies
|
Clippy currently has a lint against types that stutter, but it is disabled by default. |
|
There might be some guidance from the C++ world. In particular, Google's C++ style guide disallows |
|
IMO, Go forcing everything imported to be qualified by import name did the right thing. |
|
An interesting example is the impl fmt::Display for Foo {
fn fmt(&self, f: &muy fmt::Formatter) -> fmt::Result {
// ...
}
} |
|
That's an interesting one. For whatever reason, in my code I have found that I prefer this: use std::fmt::{self, Debug, Display};
impl Display for Foo {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
/* ... */
}
} |
|
I think this should provide at least one canonical guidance for this: https://github.com/rust-lang/rfcs/blob/master/text/0356-no-module-prefixes.md. It's about modules rather than crates, but I think the same reasons apply? I originally saw this convention at https://aturon.github.io/style/naming/README.html#avoid-redundant-prefixes-[rfc-356] too. Note that the RFC mentions |
|
As for renaming imports, the most common place I do that is |
|
I prefer |
|
Hmm, in reqwest I can see |
|
True, though the naming was because I don't expect to expose the internal "redirect" module, so they can just be 'Policy' and so on. I suppose they could internally, with a public reexport introducing the prefix, but either option doesn't seem much better in the end. |
|
So going further with reqwest as an example. Assuming that Redirect module is made public seanmonstar/reqwest#105 should its types be "destuttered" by default along with the export? Or is certain level of repetition is still encouraged as is the case Client::ClientBuilder / Request::RequestBuilder? |
|
This came up in mlua-rs/rlua#15, too.
That'd make |
|
@jonas-schievink |
|
Any conclusion? I need answers, but have no thoughts :) |
|
Not stuttering is good... I like: |
|
Renames are fine too, so long as they don't stutter. Also, I would not love seeing this (which actually stutters too): |
|
People will use module-qualified paths if they are sensible and pervasive in your documentation and usage examples. "Sensible" is a function of number of characters typed and how unique the name is. In my experience people are fine typing 2-3 character modules and mostly fine with 4 character modules. More than that is asking too much, meaning that items in a 5+ character module or library better have a name that can stand alone.
Certain items have somewhat higher thresholds between sensible and not sensible. For |
|
I've recently been thinking about this specifically in the context of errors https://twitter.com/softprops/status/1038234080305967105?s=19 Being my own devils advocate what this can lead to is overscoping of errors on focused methods. In other words a method in a foo crate that returns foo::Error but in practice may only yield a subset of the total types of errors foo::Error represents. This means clients are asked to handle a representation of errors that won't ever occur in a specific context. Yes this encourages much more focused crates where foo::Error enumerates a very small set of cases but in practice this seems rarely the case. foo::Error typically represents all the cases. |
|
The discussion of fine-grained vs broader error types is in #46. If a library or module uses fine-grained errors like the ones returned by std FromStr impls that you linked to, I would expect that they would not all be called |
|
FWIW, I’ve been very deep into Go language for the past 6 years or more. I’m so used to concise package names and qualified imports. Stuttering and the tendency to import types rather than modules in most open source Rust code I’ve seen is probably the single most annoying reason for me to start digging into Rust more. I just can’t stand it. I can never understand if a type is a third party type or is defined in the same module. I constantly have to scroll to the top to check it. And don’t get me started about obsolete imports (when people forget to remove the type from the import when they don’t need it anymore) :) I really-really wish the community was encouraged to import modules most of the time, and avoid adding module names to types. I guess occasionally importing types is fine, especially when they are very few. But the norm should be using the module as a qualifier, IMHO. |
|
What I've also seen is to de-stutter in the module where it's defined, as in: // projects/foo/src/result.rs
pub struct Result;... and then use the then non-stuttered prefix with a re-export: // projects/foo/src/lib.rs
pub mod result;
pub use result::{Result as FooResult}; |
Uh oh!
There was an error while loading. Please reload this page.
Should it be
log::Levelorlog::LogLevel? This comes up all the time and we've never really settled it as a community. So far we have tended to encourage importing types rather than modules:But this works less well if the type relies on the module name to disambiguate what it means, as in the case of
io::Result.To add to the mess, we have tended to discourage renaming imports.
How do we reconcile all of these?
All reactions