-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow T op= &T for built-in numeric types T #41336
Allow T op= &T for built-in numeric types T #41336
Conversation
Currently, there are 4 ways to add two i32's together: a + b, a + &b, &a + b and &a + &b. The same is possible for all other binary operators and for all built-in numeric types that support those binary operators. Similarly, unary operators also have both a ref and a non-ref version, e.g., -7 == -&7. However, the assignment versions of these binary operators don't allow a ref right-hand side. This commit fixes that inconsistency by implementing these operators. These changes should be fully backwards compatible.
Similarly to the built-in numeric types, Wrapping<T> supports reference arguments for unary and binary operators, but not for the assignment versions of binary operators. This commit fixes that.
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
r? @BurntSushi |
Thanks for the PR @migi! @BurntSushi or some other reviewer will be looking at your PR shortly. |
@aturon What do you think? I think these look fine to me, but I'd appreciate a second pair of eyes because these are insta-stable. It also seems like adding similar impls for |
This looks great to me, but I'll tag this with waiting-on-team as we'll want to discuss this during a libs triage. |
I'm in favor! |
Wait right we have a system for this! @rfcbot fcp merge |
Team member @alexcrichton has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
Just to note that this PR closes #32094. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
@bors: r+ |
📌 Commit e47c971 has been approved by |
⌛ Testing commit e47c971 with merge bbd636c... |
💔 Test failed - status-appveyor |
@bors retry
|
@alexcrichton, @aturon: Sorry to bring this up again, but I wasn't there in the libs triage and I didn't find any minutes or notes online, so I don't know to what extent this PR was really discussed. There are some points in favor of this PR that I didn't discuss before, because I didn't want to make this PR into a sales talk, and I thought that the blatant inconsistency between But like I said there's some other points that I didn't this elaborate in this PR before, because I didn't want to make it a sales talk. Basically, I disagree with this:
I assume this is referring to this: the upcoming ergonomic improvement to "auto-deref Copy types". This would allow, for numeric types like Well, the problem is that that is only possible if the type of Consider a function that adds The trait bound that should be used in performance-critical generic code is (you guessed it)
I'm not trying to diminish the fact that the PR breaks type inference in some cases. This PR does break existing code. That's definitely a con of this PR, and whether that con "outweighs" the pros (or rather, the cons of the status-quo) is indeed up to the libs team. You may have discussed all of these things in that libs triage already, in which case I'm sorry for wasting your time. But I have no way to tell. Actually, if backwards compatibility was not an issue at all, the best (but very idealistic) solution in my eyes would be if the ergonomics improvement "Allow owned values where references are expected (or: AsRef coercions)" were implemented very thoroughly, to such a degree that the compiler would understand that Also, what should I do with all those pull requests that I made to the crates that would be affected? Right now, 8 of these 9 PRs have already been merged (all except pijul), but those "fixes" are pretty useless if this PR is not accepted. I think I'll just let those crates be for now, they've been bothered enough. Just next time that someone submits a PR that breaks code, don't go and tell them to submit fixes before you've decided to accept their PR, that turned out not to be the best idea I think, it kinda wastes everyone's time if the PR is eventually rejected. 😉 |
@migi Thanks for the very well-thought-out reply! I agree with essentially all of it, and given that the regressions have already been resolved, think we should go forward. cc @rust-lang/libs wdyt? |
I'd personally still be hesitant to land this given the breakage. I definitely don't disagree with the benefits, but breaking nearly 10 crates in unique circumstances is quite a large change. Additionally I'd expect in abstract that idioms like I think we'd want to do another crater run before landing regardless, but I'm quite sure that if we were to land this then the breakage we've seen already is not the last we're going to hear about. |
I would also expect I also think that if What would be ideal (though I don't know how hard this would be), is to add deprecation warnings for code that relies on these type inference cases, and then in a later release enable the new trait impls (making those warnings into hard errors). That also gives closed-source code time to adapt. This could be done with an attribute like Finally, for some of the problem cases (those involving
|
@migi ah yeah that's a really good point, the inference here is a bit of a minefield and there's no use in picking a few idioms as working when other similar ones don't work. With that in mind I'd be fine having another PR for this, although I'd like to run crater again to ensure that nothing new has regressed. |
Hi, so just got sent here from this. Is this still waiting on a rebase and pr? |
@Eh2406 The reason this PR being closed was due to inferred type of |
But most importantly @alexcrichton asked for a new PR. |
@Eh2406 I don't mean |
But this is not a change to the inference algorithm. This is just adding an impl. |
@Eh2406 If we still want code like #41336 (comment) to pass without type annotation after adding the impl, the inference algorithm needs to be changed. |
True! But my reading of this thread is that we don't want that to pass without annotations. Specifically #41336 (comment) |
Allow T op= &T for built-in numeric types T v2 Manually rebase of @migi rust-lang#41336
This seems to break inference for such code: let foo: &mut usize;
*foo += iter_that_yields_usize.sum(); Is this intended? |
It is. |
On the ergonomics front, how is removing a |
The breakage is obviously not intended, but it's unfortunately unavoidable. At least until we get default type arguments for generic functions (so that the generic argument in The purpose of this PR was not ergonomics. It was twofold. The first was that the lack of the impls introduced in this PR was a huge limitation for generic numerical computation. Read this (edit: or this) for a more detailed explanation. The other reason was consistency. *foo += iter_that_yields_usize.sum(); work if *foo + iter_that_yields_usize.sum() doesn't? |
@migi Good point mentioning |
Currently, there are 4 ways you can add two i32's together: a + b, &a + b, a + &b and &a + &b. That is, the Add trait is implemented 4 times to support both ref and non-ref arguments. The same is true for all other binary operators and all other built-in numeric types, including Wrapping. Similarly, unary operators also have a ref version and a non-ref version, so for example -7 == -&7.
However, the assignment versions of the binary operators don't allow a ref right-hand side, so for example a += &2 doesn't work. This pull request fixes this inconsistency by implementing T op= &T for all built-in numeric types (integers and floats) and also for Wrapping.
There is one final type that Rust provides compound assignment operators for: Duration. I chose not to implement Duration += &Duration (etc) for now because the non-assignment binary operators for Duration also don't support ref arguments, i.e., you can't do &Duration + &Duration either.