Don't keep complicating the syntax (soft post, maybe off topic, maybe irrelevant)


I’d like to offer another opinionated observation on this matter: many proposals tend to jump straight into new syntax over the use of attributes which could often be used to achieve the same result. This has always been confusing to me because the justification for doing this is often little more than “attributes are ugly, syntax is pretty”, but I think attributes serve a very important role vis a vis how they effectively signal modifications of existing syntax and the ‘advanced’ nature of a feature.

I think Rust, as a language, could easily have thousands of different attributes available and nobody would bat an eye toward its complexity because the syntax of the language would remain the same, and the complicated semantics could be doled out in nice compact units. And beginners would not have to immediately incorporate knowledge of them into the process of understanding the grammar.


Speaking as a member of the language team: this is emphatically not our approach. There is always a default presumption of not changing the language, and that holds especially true for new syntax. We think heavily about the teachability of the language, about the total complexity budget and “divergence from anything people have seen before” budget, and about the cost of new features.

On the other hand, sometimes adding a new feature can make the language simpler, especially if it eliminates a special case and makes the language more orthogonal, and we consider that possibility as well.


Wouldn’t it then make sense for discussed features to be discussed a lot more widely? Has there been internal discussion in the language team about why people were surprised by impl Trait in argument position, and if that should be countered somehow? Things like avoiding writing the types in the function signature is I think still on the table in the type ascription proposal.

Edit: I should note that I don’t doubt that the language team does the best they can with the tools available, just that increasing visibility of contentuous issues within the community might be an additional tool.


Yes, we’ve had several discussions about why certain features turned out to surprise people, and we’ve been trying to make sure things get discussed more widely.

We’re putting a greater emphasis on “no new rationale” in language team meetings, and ensuring that the discussions we have (and not just the summaries) get reflected into github issues.

And we worked with This Week in Rust to get RFCs publicized more widely at more points in their lifecycle.


I’m not sure this will have the desired effect. I don’t think TWIR specifically highlights things like impl Trait in argument position. Same with the type ascription feature. “Type ascription” is by now a widely recognized term in the community, and the “allow type hinting expressions” part is what is usually talked about. The function signature changes are not something people are expecting, so I’d argue that that should be highlighted specifically, to gather more community input.

Edit: Fun addition: I thought I missed the RFC being slimmed down and accepted, but I stumbled upon RFC 803 (type ascription) from 2015 instead.


I think you need to elaborate on this. TWiR undeniably now includes New RFCs, RFCs in FCP, and Issues in FCP (such as stabilization decisions).

(This wasn’t always the case, so if you look at old issues it of course didn’t, but it’s clearly true now.)


My two cents on this issue:

Or as my TA of Data Structures put it: “We’re not using C++ for the course, not because we can’t, but because C++ is full of Gotchas.”

The course went from C++ to C, not because C++'s abstractions weren’t there, but because the minefield of surprises it includes make it too distracting and frustrating for students at that level.

I feel the course has gotten much better since that changed, and I think I agree with Christopher here as well. It’s not the grammar per se that makes a language more complex to use, but rather the surprises within it.


Yes, they mention the RFCs, but by title and without specifics. I don’t think impl Trait in argument position was mentioned there. I also assume the “Generalized Type Ascription” RFC FCP will have that title in TWIR, and not point out that it might contain function signature changes that might warrant more community attention.


Since you’ve mentioned this RFC a few times now…

  1. Yes - the title of RFCs should generally be kept as is as I don’t think it’s the role of TWiR to editorialize over RFCs in a way that biases in one way other based on the editor of TWiR’s (or your) opinion.

  2. The RFC’s summary describes all the relevant changes succinctly in the summary; anyone who clicks on link in TWiR should see those changes quickly.

  3. The RFC is in my view essentially (except for experimental parts) a bug fix.

  4. …The goal is to reduce surprise (what @CAD97 was talking about) by applying a rule consistently, that you can write pattern: type anywhere a pattern is expected. This is done by allowing pattern: type generally everywhere (hence the name “Generalized type ascription” and by removing the restriction on function signatures always having the type. I think this strictly removes complexity from the language and makes it easier to learn.

  5. What confuses me greatly is that on one hand you agree with @H2CO3 that symmetry is good; but when presented with an RFC that should strictly improve symmetry and which reduces the amount of things to learn (because intuitions about pattern matching hold uniformly) and which can lead to improved error messages, you disagree with it?

I think Josh said it well…

I think this is what the cited RFC does, in all respects (save for the experimental parts, but that’s why they are experimental…).

This description is misleading in my view. The RFC does not, by any means, introduce global type inference. It still remains true that the type of a formal function parameter can be determined by the signature of the function alone and without looking at the body.


I simply value uniformity of binding: Type arguments over symmetry in that case. I’m also not a fan of the above mentioned impl Trait in argument position for the same reason. I like to see where things are generic.

Either way, I didn’t really want to join into that design discussion. My point here was that the more controversial and/or surprising parts of an RFC could use more publicity.


I think the discussion is relevant to this thread because it gets to what constitutes “complicating the syntax”… I’m arguing that syntax is simplified by a large amount and that extraneous concepts are removed from the language; but you don’t seem to agree?

The problem is that “surprising” is in the eye of the beholder; what is surprising to you is just a natural conclusion / bug-fix to me.

Uniformity with what? There’s nothing to be uniform with… The only place where you must write pat: type is in formal function parameters, nowhere else (to my knowledge). The cited RFC is what makes the situation uniform…


Symmetry isn’t always good, or else we’d all be programming with SK combinators. We don’t do that as a concession that too much generality, applied too broadly, eventually hits a point of diminishing returns. (If we were using SK combinators, we may as well be writing code in binary.)

Functions being the core abstraction offered by Rust, they are a great place to break symmetry and do things differently. In fact there are many examples of this: type inference, the behavior of return in closures, etc.


I’m also not really following the argument here. I feel like some of these comments are implying that just reading the titles of RFCs in TWiR should be enough to tell you if there’s something in the RFCs you might want to object to, which seems wildly unrealistic. If you actually read or even just skim the impl Trait RFC (well, the recent one that got stabilized) you can’t really miss the argument position thing. Likewise, if you skim/read the type ascription one, you can’t really miss that it affects function signatures. And if you want to not be surprised by Rust language changes, skimming accepted RFCs feels like the bare minimum to me.


Granted, we don’t want to write in SKI / STLC (not because the symmetry is bad, but because they are useless languages – for practical general purpose work – that don’t offer enough abstractions or communication with the outside world), but that does not mean that various “subcomponents” of a system/language shouldn’t be internally consistent or compose well.

I don’t agree. It makes the language less ergonomic, more surprising, encourages longer function definitions (less readability imo), keeps redundant information, and it is inconsistent with the grammar in closures.


If you follow the thread, it started with @kornel mentioning ? as a counter example. I objected that ? semantics had a very long trial period with try!, and the main concern was lower control flow visibility.

I then contrasted that with impl Trait and the type ascription change to function signatures, which aren’t widely known, and can only be tested on nightly. Those don’t have trial runs on stable, and are far removed from how ? came to be.

So? We’re still at the point of “some things might be worth specifically calling out to the community”. Criteria can be established afterwards if there’s agreement that that is true. Language team members could just get in the habit of posting to internals or the subreddit to gather more eyeballs if they think something might surprise people, for example.

But to repeat, I’m just at the point of pointing out that it might be useful.

Uniformity with each other.

I’m not too bothered by it. I can simply avoid using that one, since it’s not an invisible feature. I just used it as an example of something that might be a surprising aspect.


Then why were people surprised by impl Trait in argument position? The whole impl Trait story is spread wide, since in return position in traits is something everyone wanted. Why did the argument position aspect never make it to those discussions?


If we really want to dig into the impl Trait example more, it’s important to point out that “argument position impl Trait” is not at all unique in its surprise. For example, I’ve seen a lot of people on other forums react to news about (return position) impl Trait with “can’t we already do this with generics?” or “can’t we already do this with trait objects?”, both of which make it pretty clear they simply never read even the most basic description of what the motivation or functionality of the feature is. Which I don’t mean as an insult; the reality is most people don’t have time to keep up with all these design discussions, so most new features are at least a little surprising to them. Most of those posts were appropriately answered with 2-3 sentence explanations of what makes impl Trait usefully different, but those of course didn’t go into detail about argument position vs return position and all the alternate syntax suggestions and so on.


I don’t think that’s actionable. What are authors supposed to do, post places saying “My RFC in controversial”?

Anyone with strong opinions is encouraged to write blog posts or RFCs of their own, which will also get publicity in TWiR.


Like I said above, if someone on the language team things some things could be surprising or have unexplored problem space, post them to internals or the subreddit. Maybe there’s relevant examples pro or against in the wild.

I want to point out that I responded to

in saying that I think more exposure can help with that. And again, this is all in the context of contrast with the amount of scrutinity ? was able to get.


Speaking of ?, I never read the original ? RFC back when ? was added to the language, and later on I was shocked to learn that try {} blocks were part of that RFC and had already been accepted into the language, even though they seemed very undermotivated to me (and as it turns out, quite a few other people on later RFC threads).

I’m not sure there’s any specific actionable lesson to draw from this. After all, I don’t want us to start stabilizing half-features just because we’re worried about public reaction to the second half. My point is that the general implication here that the way ? was added to the language is somehow more responsible than the way impl Trait was added just doesn’t seem true to me. All the problems being pointed out seem very real, but also inevitable and not new.

I feel like I should probably make some kind of constructive suggestion at this point, but I’m struggling to come up with anything we aren’t already doing. TWiR is as thorough as it can get; there’s no point asking TWiR to summarize the RFCs’ content because every RFC already comes with a summary. There was a Help test impl Trait! thread all the way back in January, which even includes argument position usage in the opening post’s example. So… I’m out of ideas.

To me, this whole thing feels to me like a symptom of the trust erosion caused by (among other things) the bizarre ergonomics RFC crunch time we had last year, rather than an actual downward trend in Rust design quality. Do we need to talk more about that?