Allow disabling of ergonomic features on a per-crate basis?


#1

The introduction of match ergonomics has been fairly controversial, it seems. Many Rust users that don’t familiarize themselves with active RFCs were caught unaware by it, and for users like myself who prefer more explicit code it has been nothing but a distraction.

Even if explicit matching on references and so forth (like we did in the past) is a bit noisier, I can instantly see what borrows and types are happening without having to sit down and rethink the entire segment of code. Match ergonomics and default bindings introduce too much ambiguity for my taste.

Would it be unreasonable to ask that we be allowed to disable any past, present and future ergonomic features on a per-crate basis if we prefer to write more explicit code?


#2

Technically speaking, we could introduce allow-by-default lints which you can then #![forbid(the_ergonomic_feature)].

From a perspective of having a cohesive understanding of the language and usage of it across community it seems like a bad idea.


#3

We have decided not to allow users to enable or disable individual features on stable to avoid a dialectical explosion.


#4

I’m not sure what you mean by that. Ergonomic features are language features where both the “short-form” and fully explicit form are correct code, right? Additionally, they would never appear in any external API such as with public crate methods, so there is no risk of conflict with any other crates or project. It is purely a personal choice.


#5

Every flag complicates the compiler.


#6

You are not incorrect, I know that. There are dozens if not hundreds of flags and lints.

To me, moving from explicit types and borrows on match arms and elsewhere to implicit “ergonomics” feels like going from the explicitness of generics with trait bounds back to implicit C++ templates that allow nearly anything. I want the compiler to yell at me when I do something stupid, not just automatically adjust the code to fit.


#7

The position you express about this feature was well represented in the RFC process, but ultimately we decided to accept the feature. Just about every feature has people who don’t like it for whatever reason; it wouldn’t be reasonable to make a flag to turn off each of them.


#8

I’d recommend to file an issue to clippy for including a lint for autoref/deref in patterns.
Clippy is kind of aligned with the lang team though, so if that doesn’t work out, you’ll may want to fork clippy and add the necessary lints by yourself. This is not so hard (there’s a tutorial - https://github.com/rust-lang-nursery/rust-clippy/blob/master/CONTRIBUTING.md#writing-code) and may be especially reasonable if you have several such custom lints or need other people (e.g. team) to follow same style.


#9

What I think they mean is that any language feature that is allowed to be feature gated in the way you describe would split the Rust ecosystem at least in 2, or even more if the feature gate ever got arguments. If then there ever was a new feature gate added, suddenly the language would be split into 4+ camps, and so it explodes exponentially for each new feature gate.

This is a Bad Thing in the same way that the C++ world being splintered into many many groups, each speaking a different dialect of C++. Migrating to any new project in that ecosystem can mean not only familiarizing yourself with a new code base, but also at least a new style and perhaps new language features, depending one’s own knowledge at the time and the dialect used. In other words, it just adds friction to the ecosystem, complexity to the compiler, and there’s no real upside for most(?) people.


#10

Is there a tool that can de-sugar and explicitly show the result of type inferences into valid rust code? I think something like this would be very useful for learning (e.g. lifetime elision) and could also be used as a git commit hook or similar to enforce explicit-as-possible code.


#11

I believe RLS can do that, or you can just put as () to get an error telling you what type it is.


#12

This feels to me like a code-style question, which other languages typically handle through linters. TSLint is a great example of a linter which has rules that are opinionated on feature usage.


#13

The IntelliJ Idea Rust plugin (and CLIon with the same plugin) does this automatically by default. It’s one of my favorite features.


#14

Maybe ergonomics should be part of the IDE. Then everyone wins: there’s one strict, canonical way to write Rust, and anyone can configure their IDE to look nicer.

It’s basically a per-user feature flag, rather than per-crate.


#15

While IDE’s certainly have a part to play in the Rust development experience, I do not agree that ergonomics are something that the IDE is supposed to deal with.

For example, look at Java: There are a couple of fairly advanced IDE’s, but I’d argue that at least part of that was a response to Java’s total lack of ergonomics at that time. For example, code templates were added because it can be more convenient to use that than manually writing public static void main(String[] args) { ... }, or emulating closures with anonymous inner class instances and the like. Had Java been more succinct in such matters, such a code template feature might never have existed.

Conversely, when the language itself is ergonomic, that leaves free effort to spend on other things. Like bikeshedding what “ergonomic” even means in the context of a programming language :slight_smile:


#16

at least java didn’t introduce semantic ambiguities.


#17

I myself am not fan of some of the ergonomics features, precisely because they feel like the mental model is no longer as firm/strict and that the types in my mind have a space to „rattle“ around a little bit. I just hope my code won’t become more bug-eaten as a result.

But even in that light, I wouldn’t want to open the pandora box of having multiple Rust dialects (rust-strict, rust-ergonomic, …), accepted and subsets, etc… currently, I can take almost whatever crate there’s on github or anywhere else and start hacking at it without much learning about styles, accepted idioms. Having a less strict compiler seems like the lesser evil (because, after all, I’d still have to meet code that does allow the ergonomic features and make a distinction on top of that).

If it indeed turns out after some time the <whatever feature> wasn’t that great, it can be turned into a warning ‒ but I think it should be done „globally“ as well ‒ after an RFC, whole-comunity discussion that it indeed was bad, etc.


#18

I’ve already run into situations once or twice where the match ergonomics have introduced references I didn’t know about, and for that to bite me later on when I modified the code. It’s awkward to reason about values that may or may not be references.

Furthermore, my argument was to allow only ergonomic features to be disabled, either via lints or whatever. They are the only opinionated syntactic sugar I can think of that has been added recently.

Even the ? operator is totally optional. impl Trait is optional (although very useful, obviously).

Match ergonomics are forced, everywhere, even in places you wouldn’t expect like in structure destructuring.


#19

I really have to disagree that people deciding not to use some feature is somehow creating dialects, or fragmenting the language. Everyone always only uses a subset, and “you don’t have to use it” has a long tradition as an argument to minimize the effect of downsides.

Are people who don’t like variable shadowing creating a dialect? How about people like me who don’t use fn foo<T:Clone> bounds but always use where clauses? Loops versus iterators? People who don’t like impl Trait in argument position? Another form of specifying trait bounds has just entered FCP-merge.

At some point Rust has to decide if it wants to be a “many ways and trust people to choose the right one” or a “one way and everything else is wrong” language. If choosing not to use a feature is community fragmentation, so is adding one not everyone might want to use.


#20

FYI: I have opened a clippy issue about adding an opt-in restriction lint to at least allow enforcing consistency in matching in the places I care mostly about.

It might be helpful if people could contribute their usecases there.