-
Notifications
You must be signed in to change notification settings - Fork 1.6k
RFC: rename lifetime
to scope
#431
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
Conversation
Don't you mean "associated scopes"? |
For what it's worth, I believe that a different metaphor (based on "locks" perhaps), is likely to work better for |
This change introduces some additional ambiguities, e.g. what do you mean when you talk about the scope of a borrowed pointer? I guess you could refer to the borrow scope of a borrowed pointer as suggested, but that is also slightly ambiguous in that it could possibly refer to a borrow of the borrowed pointer itself. What are lifetime variables and parameters called? The terms "scope variable" and "scope parameter" seem really strange to me. What do we call the |
@wycats As far as I understand it, the proposed changes for the extent of a borrow apply to any kind of borrow, and it's not too hard to find situations where non-lexical, immutable borrows are useful. Does this change your opinion? |
I think we would say |
The proposal in #396 is to change the inference of all lifetimes, regardless of the particular kind of borrow involved. In a case like |
Right, "borrow scope" serves a general disambiguating role. I think the second situation is equally problematic for "lifetime" (or any other term).
We generally refer to
Probably just that |
@aturon I'm not entirely sure why changes the extent of a borrow should be necessary when overlapping borrows are allowed. Ah! This is for the case where there is an |
@aturon I have found that "a larger scope" is good for general discourse, and "an upstream scope" is good for initial teaching, especially when you have the code in front of you and can point at the various physical scopes. |
Overall +1, I've encountered confusion around the term lifetime many times now, where people assumed it was linked to when the destructor executes. I do like pronouncing |
Yay! I've thought this would be a good idea for a while now. (It's why I sometimes use |
I like this change, "scope" is more familiar to most programmers and makes this easier to grasp. We'll need to figure out a new word for "outlives" as Niko said, though. "Outlasts" seems fine. |
I worry that this change will make it difficult to communicate clearly about both scopes (lexically contiguous regions of tokens within which names are bound) and lifetimes without confusion. These are simply two distinct (but related) concepts, and both of them are important for users of Rust to understand. "Scope" is already a complex term because the word on its own tends to serve as an abbreviation for the actual intended meaning: a "scope" in common parlance is short for "the lexical scope of a name binding". Those with no prior programming experience may fail to distinguish between these until helped (hindering understanding of both), and those with prior programming experience will likely be confused by the use of a familiar term to refer to an unfamiliar concept. The real slip-up that I see newcomers making with respect to lifetimes in Rust is that they expect lifetime variables to be /prescriptive/ rather than /descriptive/. That is, they think that lifetime annotations direct code generation (when to call destructors, &c.) rather than typechecking. I think this should be addressed, and likely some name change might help, but using an already complex term like "scope" would probably not be the right way to attempt to prevent this pitfall. I personally would suggest explicitly distinguishing between lifetimes of values and lifetimes of borrows. The former (understood in the sense of https://en.wikipedia.org/wiki/Object_lifetime) have never been lexical, as via moves a value can live through multiple functions whose bodies are not lexically contiguous. Lifetimes of borrows (which are denoted with lifetime variables) cannot span moves of the borrowed value, so they will ultimately refer to something which is some maybe-disjoint subset of the lexical area of a single curly-brace block (ignoring 'static). It would be nice to always distinguish between talking about "borrow lifetime" vs. "object lifetime", but "scope" on its own is already taken and I hesitate to introduce "borrow scope" and complicate what "scope" might refer to. |
I though sizes didn't matter. More seriously, I don't think "larger" conveys the right meaning, as it's not only larger but also that it contains the other scope, isn't it? I'd suggest something like the scope of a contains b (or a contains b). |
I don't like this, as per the introduced ambiguity and inability to solve the pre-existing ambiguities highlighted by @sp3d. It's not at all obvious to me that replacing the object/borrow lifetime ambiguity with lexical/borrow scope ambigutity results in any overall improvement. Neither term in isolation has the meaning Rust wants it to have, so it seems pointless to change it. |
The biggest argument in favor of this change is that multiple people (including me!) report having had an epiphany about how lifetimes actually work and what they mean after they were described to them in terms of scopes, instead. (In my case, this is after having persisted in various misguided notions about their meaning based on the word "lifetime" for the preceding several months.) This suggests that "scope" is a much more useful intuition than "lifetime" in practice. Why this is so is something that's open to debate, but that many people have had this experience is an empirical fact. |
Seems like a moot point for the future, when lifetimes will be non-scope based. Even today, temporary lifetimes have nothing to do with scope.
Without computing the fraction of total number of Rust users that had this experience, you can't draw concrete conclusions about this beyond that 'it helps some people'. Personally, I don't find the analogy that useful, as it doesn't actually help resolving the really tricky borrow check errors. |
First off, I wonder if keyword-less associated items were ever considered, e.g.: trait Trait { T; 'a; }
trait Trait { T: *; 'a; }
trait Trait { -> T; -> 'a; } These are by no means a complete proposal, but I'm interested in a general reasoning for needing a keyword, is it actually impossible without? I was going to point out how "scope" is closer to "lifecycle" rather than "region" (which I tend to exaggerate trying to redefine as "relative time range variable" or many other similar phrases). |
@nikomatsakis: I doubt people are confused because it is called "lifetimes", but because they are a new and novel concept to many. I do believe that naming it scope however will lead to confusion. People know about "dynamic" and "lexical scopes". At least with "lifetime" it has a unique name. I'm actually a bit surprised. The RFC makes it seem that you can use the right word and most people will intuitively know what I'm also a bit afraid of having to talk about "scopes", "borrow scopes", "borrow scope variables" and so forth. It's just lots of terminology overloading. There was a change from Addendum: I think the crux of what irks me is that in
|
I would agree with @phaylon. How about a (borrow) duration? Borrow period? Lease? To stay with the (great) metapher of borrowing a book or something else.. :) For me it was always well understood that the lifetime does not reflect the lifetime of the original object, but the lifetime of the borrow and i think that was made clear in the tutorials/guides. |
I'd even say lifetimes are beyond borrowing. I'd have a hard time explaining memory management, it's additional syntax, and resulting compiler restrictions without often using the term "lfietime" :) I do agree that certain things can be "lifetime scopes", or that scoping itself is relevant to lifetimes. I disagree that putting it all under the "scoping" umbrella will simplify things. The fact that I'm a non-native engilsh-speaker might influence this. Edit: Fixed s/lifetime/scoping/ misuse. |
I disagree here, the concept of object lifetime is common and well understood. There's a wikipedia article about it even
But how is scope any different in this respect? Surely people could have the same misconception "so at the end of a scope, you'd expect the relevant object to be destroyed. But in fact, it is exactly the opposite: as long as there is a borrow with any scope, the borrowed object cannot be destroyed" |
+1. Scope is a much more friendly name and much more common in the programming world. |
👎 IMHO this is a really bad idea. Lifetimes are what is different and better about Rust. Precisely because "scopes" have a common and somewhat consistent meaning in other languages, we should avoid this change in terminology. Vote NO on PR 431 |
Bad idea from both points of view:
|
My initial thoughts on this are that it seems counter-intuitive and generally unnecessary. I posted my reasoning here. I can understand why some of the core Rust devs might feel like there must be something confusing about the lifetime name after watching lifetimes become the primary source of confusion for new folk over the past year/s, however as a recent Rusty recruit I feel obliged to suggest that this probably has a lot more to do with the concept itself rather than the name. It is possibly the newest concept that Rust offers as a language and it is related to pointers, one of the most renownly difficult areas in low level programming for beginners. I think rather than spending pre 1.0 time on this we'd be better off embracing the fact that lifetimes are one of Rust's newest and iconic concepts and pouring more effort into friendly docs / tutorials / examples for helping the curious/confused new-comers. |
Just to be clear, I don't really mind either way, but I think a lot of the objections here are based on the notion that "scopes" are as likely to confuse newcomers as "lifetimes." I don't think that's true, because when you're actually reasoning about lifetimes you do basically look at scopes and figure out how they overlap (maybe this will change with SEME). It's not a perfect name, but neither is lifetime. |
Scopes usually have the property that two scopes are either disjoint or one contains the other. On the other hand, there are proposals that would allow lifetimes to be overlapping without containing each other (e.g. RFC #396) In that case, "scope" seems an inappropriate term. |
My experience teaching has been that people are confusing about lifetimes at least partially because of the term (though naturally for other reasons as well). They tend to think that when I make a reference to a value, the "lifetime" of that reference is equal to the scope in which the destructor will run, but this is not necessarily the case. When I have switched to using the term "scope", it has materially helped, and introduced no particular confusion. Consider an error message like:
as compared to
There are clearly two distinct concepts at play here. The lifetime, in this more restricted sense, is a very specific scope which is tied to running the destructor, whereas the borrow scope is some subset of that. Scope has that advantage that it is tied in people's minds to spans of the source code. I think this is crucial. It is true that the scope of a borrow doesn't have a 1-to-1 correspondence with lexical scopes, but I think this is a relatively minor point that can be separately addressed. (And there are already many uses of the word scope beyond just lexical scope.) The alternative in my mind is a word relating to time, e.g., duration, timespan, or interval, but this often carries false intuitions about wallclocks and so forth. |
@nikomatsakis: I'm having a bit of trouble understanding that. You say lifetimes are confusing because people equal them to scopes, but calling them scopes directly makes people not do that? The main point of confusion might be that I understood the RFC as changing all lifetime terminology to scope terminology, but perhaps it is a more borrow-centric idea. I guess I could summarize my view as:
Could the RFC maybe contain more concrete examples of what is to change? For example I'd have no problem with documentation referring to a "borrow scope" or something of that nature, it's just that a "scope" itself is quite overloaded. I'm also not really concerned with the name of keywords, though I like them to be consistent with terminology. My main concern is my ability to give explanations that contains concrete terms that people can look up. Searching for "rust lifetimes" or (to a subjectively lesser extent) "rust borrow scoping" seems like it'd give better results than just "rust scoping" and sorting out the rest. |
I'm very excited about this change, especially given the overwhelmingly positive experience we've seen so far with explaining these concepts to newcomers. Personally I believe the real experience should trump a priori reasoning. Nevertheless here is how I personally (I wasn't the only one or even the first) came to the conclusion that scope is a better term. The key distinguishing feature about "scope" here is that it corresponds to a static reasoning discipline rather than a dynamic one. A scope is a static portion of a program; a lifetime is a dynamic extent of a program execution. This is related to what people were discovering in the structured programming era, e.g. Dijkstra's famous essay about goto: My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible. The discipline enforced by the type system actually does correspond to the relationships between static regions of code (hence the original research literature's use of the term "region," but unfortunately that word does not unambiguously connote a static concept), not the relationships between execution traces. The lifetimes are a consequence of the programming discipline but not the discipline itself. Re: confusion with lexical scope, using "scope" informally to mean a region of code is common usage and easily explained, and "borrow scope" disambiguates it. We mustn't let language pedantry (spoken as a bonafide, credentialed academic pedant here...) stand in the way of approachability. Re: non-lexical regions, this is an instance of hard cases making bad law. When you teach, you start with simplified intuitions and refine them as you go along. You cannot throw everything at a newcomer at once, or you blow past what teachers call the zone of proximal development and students (think: people you are trying to get to adopt Rust...) shut down and give up. Besides, non lexical scopes could be described as implicit scopes. |
I think ownership and borrowing are the interesting things that make Rust different, and I think those are the terms we want to emphasize, not lifetime (or scope). Lifetimes are just a way of referring to the scope of a borrow. If you look at http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ you can see a pretty thorough introduction to the ownership concepts that make Rust work, with almost no mention of the term "lifetime". This is the kind of presentation I'm hoping for. |
A key point, which was not emphasized enough in the RFC, is that borrowing and ownership are the actual new and interesting concepts; lifetimes are actually just a way to express the scope for which a value is borrowed. Scopes are something that programmers already understand, but "lifetime" makes them feel like something new. By de-emphasizing lifetimes in favor of "scope", it becomes possible to put the focus on the interesting thing -- borrowing. |
I don't think this is correct. There are a lot of mentions of "lifetime parameter" in error messages. There are even more in comments and GitHub issues. What term will replace these? |
So, while i agree that borrowing and ownership are good terms and i found On Mon, Nov 3, 2014 at 7:04 PM, Aaron Turon notifications@github.com
|
I very much agree. To me, "lifetime" tends to suggest lifetime of values, whereas "scope" tends to suggest (subset of) a lexical area, which is another way of understanding the proposed change. As @nikomatsakis suggested above, this would even allow us to use lifetime-related terminology to discuss the lifetime of a value, as distinct from the scope of a borrow. |
Yeah, this was mentioned in the Alternatives section of the RFC. The problem is that English doesn't have a very specific, compelling word here. You end up with things like "term" or "duration" that are not specific enough to bring along the right intuitions (I think). |
I don't understand why intuitions need compiler support. I am 100% sure that one day there'll be a better analogy for lifetimes than 'scope', that will be used in a tutorial context. Will we utilize the same reasoning to break backwards compatibility to change the name of this concept for the third time?
I don't understand what that sentence means. Do you mean, duration of a borrow? I'm being very serious here, I don't understand how using 'scope' is appropriate in that sentence. Clearly, people are raising the issue that 'scope' doesn't mean this, which makes this usage circular at best.
Well, sure, the article that doesn't deal with lifetimes doesn't mention them. If I were to write an article titled 'Rust means never having to allocate in the lexer', where I'd describe how to use Rust to write safe, efficient lexers, I'd talk a lot more about lifetimes. I really don't understand what that example is meant to show. As an aside, while lifetimes are not at the forefront of Rust's exciting features, I will claim that they are hardest feature to master. There is nothing difficult about ownership, or borrowing per se. It is easy to resolve ownership errors in code. But resolving borrow checker errors? This is the most frustrating parts about Rust programming. The amount of time I spent (wasted) contorting my code to pass the borrow checker is very depressing. |
@SiegeLord ditto -- continually changing terminology doesn't seem like a good idea |
@brycefisher it is if the new terminology makes things easier for new-comers. |
@tshepang that seems to be in question here. Some people find it intuitive, others do not. One thing we can confident of is that we're issuing a breaking change in the terminology. I'm seeing this as beneficial change personally, but I guess time will tell. |
Personally, I would go for precision with the official terminology, and leave the analogies to the tutorial makers. |
In the case Anyway, I'm happy to see some discussion about this. Many newcomers see the term lifetime and think it's some mechanism to let them control the destruction of an object. |
I believe this change will lead to unnecessary confusion, as newcomers to Rust will confuse an old concept that they're already familiar with, (scopes) with a concept that is maybe not so familiar (lifetimes) and think that they're the same, which actually they're not. |
-1. Lifetime is an established concept. Rust lifetimes are the exact same thing. |
@Jurily, they are not exactly the same. see, e.g. #431 (comment). |
Currently, lifetimes are lexically scoped, but with #6393, lifetimes will not always be lexical scopes, which further differentiates between scopes and lifetimes. When people think scopes, they think lexical scopes, so if you tell them that rust has scopes, but mean different things in different contexts, wouldn't that be confusing? Or am I missing something? |
I strongly disagree with this change, as I believe it would have significantly hindered my understanding of what Rust was offering when I discovered it. Coming from C and C++, I was already very used to thinking about how long objects and references lived (lifetimes). When reading about Rust, I was able to quickly understand what it was offering with respect to statically checked borrowing and enforcing lifetime dependencies between objects, and I was very excited about it. I had no trouble understanding that object lifetimes were determined by blocks, like in C++, and that borrow lifetimes allowed the compiler to ensure that no references were left dangling (i.e., lifetime annotations are descriptive, not prescriptive). I think of "scope" primarily with respect to name resolution. A variable is in scope if it can be named. In C++, scope is related to lifetimes, but the two are often not the same. As an example, in a function, variables in the calling function are alive, but not in scope. Also, the Thus, while I understood and was excited about borrowing and lifetimes right away, I would have had more trouble figuring out what was going on if the introduction talked about "scopes", and perhaps not been intrigued enough to take the time to do so. |
-1 for all the same reasons. There is absolutely no need to overload "scope" term even more, and given that lifetimes will be non-lexical per corresponding proposal, they will differ even more than now. |
-1 In addition to what the others said, I'd worry the name change would bias people against the proposals to make lifetimes less lexical. |
Given the clear feedback from the community, the little time remaining before 1.0, and after discussion with the core team, I'm going to close this RFC. |
* initial commit * update implementation plan * formatting * proofreading * disclaimers * say where conversion guides will go * update to list syntax for vue comparison * Update and rename 0000-guides-restructure.md to 0431-guides-restructure.md * Add reference section w/Accessibility * Add tracked to state management, suggested by gossi * Clarify naming of "handlebars" as suggested by nullvox and gaurav * Update 0431-guides-restructure.md * rename debugging to developer tools * make it explicit that these efforts don't block Octane * reunite template syntax and helpers * Add audience section * audience hypothesis * add editions guide explicitly to the upgrading section * fix markdown formatting bullet points * more bullets formatting * Update text/0431-guides-restructure.md Co-Authored-By: jenweber <jen@biobright.org> * Update text/0431-guides-restructure.md Co-Authored-By: jenweber <jen@biobright.org> * Update text/0431-guides-restructure.md Co-Authored-By: jenweber <jen@biobright.org> * Update text/0431-guides-restructure.md Co-Authored-By: jenweber <jen@biobright.org> * Add tracking issue
This RFC proposes to rename "lifetime" to "scope". This is almost
entirely a change to documentation and error messages, but it also
affects the keyword used for associated lifetimes.
Rendered