Skip to content
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

librustc: Copy or move upvars by value. #14501

Closed
wants to merge 1 commit into from

Conversation

pcwalton
Copy link
Contributor

Closes #12831.

This breaks many closures (about 10%) that look like this:

let mut sum = 0;
f.map(|x| sum += x);

Instead, rewrite them like this:

let mut sum = 0;
{
    let sum_ptr = &mut sum;
    f.map(|x| *sum_ptr += x);
}

Or, ideally, switch to RAII- or iterator-like patterns.

[breaking-change]

r? @pnkfelix

Closes rust-lang#12831.

This breaks many closures (about 10%) that look like this:

    let mut sum = 0;
    f.map(|x| sum += x);

Instead, rewrite them like this:

    let mut sum = 0;
    {
        let sum_ptr = &mut sum;
        f.map(|x| *sum_ptr += x);
    }

Or, ideally, switch to RAII- or iterator-like patterns.

[breaking-change]
@alexcrichton
Copy link
Member

For affecting 10% of all closures, a 6 kloc change seems a bit excessive, are we sure that the data was accurate?

@alexcrichton
Copy link
Member

Specifically, I was under the impression this would be a pretty small change, and this is much larger than I thought it would be. It looks like each site requiring treatment is taking a step backwards in terms of readability, and having that step backwards taken across the entire codebase is unfortunate.

@@ -1 +1 @@
Subproject commit 0a894645cf120539876e9eb4eb0d7b572dfa9d14
Subproject commit 4b4d0533b4f76cc3fbba31bd9e7ac02e0c738b1d
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unintentional.

@lilyball
Copy link
Contributor

I agree with @alexcrichton, there's a significant readability cost to all these modified closures. This suggests to me that we should rethink the idea of having syntactic sugar for auto-generating these references.

FWIW, ignoring whitespace, the diff is +2991/-2407, which is a bit better than +3864/-3280

@pnkfelix
Copy link
Member

Just a reminder, counting the lines from the diff is going to conflate the changes that come from the compiler hacking to remove up-var-by-reference support with the changes that are fallout from that hacking.

The former is the reason for the majority of the changes to src/librustc/middle/mem_categorization.rs, for example.

It may have been nice to try to separate out those two things into two separate commits (i.e. remove up var by-reference usage first and then remove support for it in the second commit), though I admit that doing so probably would be somewhat painful to maintain.

@pcwalton
Copy link
Contributor Author

There are something like 5,000-6,000 closures in all of rustc, so the data is accurate.

It is possible we need capture clauses. Let's not debate this here. It is clear that whatever syntax for capture clauses we may or may not come up with will be layered on top of the current unboxed closures proposal, and therefore should require a new RFC and should not prevent this from landing.

@alexcrichton
Copy link
Member

This PR is for an RFC that has not been accepted (rust-lang/rfcs#77), and it was agreed upon based upon the data that you collected, so I just wanted to ensure that the data is accurate. If there are inconsistencies, then we're accepting that RFC under false pretenses, which seems like something we should definitely deal with now, not later. I'm not saying we should debate about capture clauses.

It looks like your data only deals with the class of upvars being capture, but it sounded like you were surprised by a few use cases when implementing this. Some upvars were copyable, but they needed to be captured by reference (due to how they were used in the closure). Does your analysis take into account these use cases, or are they accidentally outside the originally counted 10% of closures that needed to change?

One of my worries is that this new by-val capture is double-bad where you need by-ref captures. Not only do you have to create another local for the capture, but you also have to indent the entire closure by creating a new scope to kill the borrow. This is a fixable issue, but it will seriously reduce the prevalence of closures in libraries to do what would possibly otherwise be simple tasks.

I also agree with @pnkfelix that this is difficult to review because it's all jumbled together (and github is super slow at huge diffs). Could you at least separate the rustc analysis changes, and then per-library migrations? It may also be ok to have rustc analysis changes and rustc-library migrations in the same commit (just splicing this commit up by folder in that case).

@pcwalton pcwalton closed this May 30, 2014
@pcwalton
Copy link
Contributor Author

If you have objections to unboxed closures be clear about that. Otherwise vague "worries" about this PR are extremely unhelpful. Even if you want capture clauses, this is a necessary step toward them and objecting to this PR is completely unproductive.

@pcwalton
Copy link
Contributor Author

And yes, as I stated above I have no reason to doubt my data. There are just a lot of closures in rustc.

@pcwalton pcwalton reopened this May 30, 2014
@lilyball
Copy link
Contributor

@pcwalton I really want by-value closures. And I'm strongly in favor of this PR. I don't doubt your data either. My comment was just meant to say that we need to think about capture clauses sooner rather than later, but I did not intend to imply that it should block this PR.

@alexcrichton
Copy link
Member

I concretely asked in my last comment about whether this use case was captured in your data as a closure that needed to be modified:

let mut a = 2;
let foo = || { a = 4; };

Your data looks like it classified upvars based on their type, not how they were used. This upvar has a copyable type, and it looks like your data classifies it as a copyable upvar. Your statistics would then include this as a closure which doesn't need to be modified. How does this closure get classified in your data?

I'm still not opposed to this change, I wanted to verify that your data was accurate because this was much larger than I was expecting. If there really are 5172 unmodified closures, then this seems like it's still beneficial. I was just expressing that on the surface it appears that the data you collected may be inaccurate, and was curious if you discovered anything during this migration which would cause you to revise your results.

@pcwalton
Copy link
Contributor Author

The statistics would have considered that a mutable borrow, so it would have counted it as one of the closures that needed to change.

@pcwalton
Copy link
Contributor Author

I apologize for snapping at you.

@alexcrichton
Copy link
Member

Sorry if I sounded like I was bashing this, I think that all of us are very eagerly awaiting unboxed closures!

@pnkfelix
Copy link
Member

@pcwalton If you do not object, I was thinking of breaking up your PR into separate commits segregating the separate language changes versus fallout-from-those-changes. I figure that doing so will force me to be thorough in my review. Do you object to this?

@pnkfelix
Copy link
Member

pnkfelix commented Jun 3, 2014

closing in favor of the history-edited PR #14620

@pnkfelix pnkfelix closed this Jun 3, 2014
bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

by-ref closure capture semantics are a backwards compatibility hazard
4 participants