Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for RFC 2115: In-band lifetime bindings #44524
Comments
aturon
added
B-RFC-approved
T-lang
labels
Sep 12, 2017
This comment has been minimized.
This comment has been minimized.
|
@aturon Could we word the unresolved question as something like "what is the appropriate convention, if any" rather than "is this particular convention worthwhile"? Thanks! |
This comment has been minimized.
This comment has been minimized.
|
also, that wasn't the only suggested alternative. There is also completely explicit lifetimes using |
This comment has been minimized.
This comment has been minimized.
This supposedly ergonomic change is going to require updating a lot of code, including all of our docs and examples. I guess you could just do |
This comment has been minimized.
This comment has been minimized.
|
@glaebhoerl Done, thanks! |
This comment has been minimized.
This comment has been minimized.
|
I expanded the unresolved question a bit. |
nikomatsakis
added
E-needs-mentor
WG-compiler-front
T-compiler
labels
Sep 15, 2017
nikomatsakis
added this to the
impl period milestone
Sep 15, 2017
aturon
removed this from the
impl period milestone
Sep 15, 2017
TimNN
added
the
C-tracking-issue
label
Sep 17, 2017
This comment has been minimized.
This comment has been minimized.
Mentoring instructionsI'm not sure 100% the best way to implement this yet, but let me start by giving some pointers. Perhaps @eddyb can elaborate, as he is the last one to touch the relevant code in a serious way, as far as I know. First thing is a kind of list of what the tasks are in the RFC. This is roughly the order in which I think we should approach them. It may even be worth breaking this out into separate issues. XXX task list moved into main header I don't have time for detailed mentoring notes, but here are a few things to start reading into. At present, region resolution etc kind of works like this:
|
This comment has been minimized.
This comment has been minimized.
|
To support
|
nikomatsakis
referenced this issue
Sep 21, 2017
Open
In-band lifetimes: Lint against single-use lifetime names #44752
nikomatsakis
added
E-mentor
and removed
E-needs-mentor
labels
Sep 21, 2017
bors
added a commit
that referenced
this issue
Sep 22, 2017
nikomatsakis
removed
the
E-mentor
label
Sep 25, 2017
petrochenkov
referenced this issue
Oct 3, 2017
Open
Add levenshtein distance based suggestions everywhere #30197
nikomatsakis
referenced this issue
Nov 14, 2017
Closed
lint against "silent elision" in structs/enums/etc #45992
bors
added a commit
that referenced
this issue
Nov 23, 2017
This comment has been minimized.
This comment has been minimized.
Sorry that I come “after the battle” (this RFC was accepted during the pre-impl-period rush), but as @durka pointed out applying this lint to existing code bases will likely generate a lot of busy work for questionable benefits. I looked for the rationale for this lint but couldn’t find it. https://rust-lang.github.io/rfcs/2115-argument-lifetimes.html#lifetimes-in-impl-headers mentions a “convention”, but doesn’t say why enforcing it is important enough to warn by default. We don’t have such a lint for local variable names or field names, for example. I assume that proposed lints are intended to warn by default. If they’re silent by default I have no concern. |
This comment has been minimized.
This comment has been minimized.
|
The idea is that there will no longer be |
This comment has been minimized.
This comment has been minimized.
|
@rpjohnst Sorry, I have a hard time figuring out if your comment is arguing for or against something, and whether that thing is the lint I mentioned or some other change proposed by this tracking issue. |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin It's just trying to describe the reasoning behind the lint's existence, not necessarily argue for or against it. |
This comment has been minimized.
This comment has been minimized.
|
I want to speak up in favor of having some signal that there are "hidden lifetimes" in types. The current notation of What I find is that I am constantly wanting to know whether a type contains references or not. It tells me a lot about how the type can be used: types without lifetimes can be cloned or copied and stored for arbitrary amounts of type. Types with lifetimes are always temporary in scope and confined to some caller (modulo longer lived arenas like I suspect that I derive outsized value from this notation because my intuitions for this stuff are stronger than most (can't imagine why that might be). But I feel like having a consistent syntax that highlights where lifetimes are and where they are not might wind up being very important for helping other users to develop these annotations. OK, let me give a few examples that I've run across recently. Just yesterday I was reading into the futures code and I saw this: fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output>Now, I know that a rust/src/libcore/task/context.rs Lines 18 to 25 in 79fcc58 Note: to make matters worse, rustdoc actually hides these references, so it's actually quite hard to figure out what is going on. Anyway, then I kept reading, and I encountered this signature: pub fn will_wake(&self, other: &Waker) -> boolHere, I was confused for quite a while, because I misremembered that Another example comes from the rustc source, which for a long time contained a function like this: pub fn predecessors_for(&self, bb: BasicBlock) -> MappedReadGuard<Vec<BasicBlock>>It happens that This same principle applies to compiler error messages. There, it's quite nice that we have something we can highlight to show you which reference we are talking about. e.g., we can now give errors like this: fn foo(x: Blah<'_, T>) { .. }
^^ let's call this lifetime `'1`Here, I imagine that we can find other solutions (and in general I'd like to work on improving these messages in lots of ways), but in general having a visual signal for where references are will always be useful to us, I think. As far as consistency goes, I think there is value in trying to close the gap between the various ways that you write types in Rust. Right now, types that appear in function signatures and those that appear in struct declarations sometimes look really different (e.g., |
This comment has been minimized.
This comment has been minimized.
I agree that this is not pretty, but I'm not sure that just a plan
Speaking personally, I find the I think ultimately I agree with @aturon's comment here:
|
This comment has been minimized.
This comment has been minimized.
|
I should also add that I appreciate that typing |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis Did I miss a part of your comments, or did you not address the specific suggestion of only requiring explicit
The elision aspect would cover that. And IMO I find that far more interesting than being able to tell whether a type is parametrized when looking at an universal function. I'd rather have IDEs and |
This comment has been minimized.
This comment has been minimized.
|
@eddyb I did not specifically address that. I agree that is better than the status quo. It might be a good place to start, given the controversy of the more encompassing proposal. However, I don't find this to be true:
That is to say, I personally get a lot of value from knowing whether types are parameterized when looking at universal functions. Often, when somebody pings me with some lifetime error and associated source, the first thing I do is to spend a while figuring out "where the lifetimes are". Currently, this requires jumping through to the source of all the various types involved. I agree though that there is a cost of heavier notation. |
This comment has been minimized.
This comment has been minimized.
|
Is there a lint that warns against elided lifetimes in types (I mean everywhere, not just in return position)? I'd like to see how much of an effect that has on a few projects I'm familiar with -- and if it's not too bad, it might change my opinion. |
This comment has been minimized.
This comment has been minimized.
|
@stjepang try |
This comment has been minimized.
This comment has been minimized.
|
Or even |
This comment has been minimized.
This comment has been minimized.
|
Ok, I've just run the lint on all the The vast majority of the reported warnings are either missing lifetimes in return position or in Still, the large PR (around 550 lines were changed) submitted on Then I went on to calculate the ratio of warnings per total lines of code in those projects. Perhaps I think my opinion has changed so allow me to make a 180 turn and give a |
This comment has been minimized.
This comment has been minimized.
In https://github.com/rust-lang-nursery/futures-rs this results in 511 warnings (from 15028 lines of code according to tokei (including tests which I did not try building with the warning)). Scanning the output I'm relatively confident that every single warning is for an input parameter that is not connected to the output in any way, so would result in no warning for the "explicit lifetimes when elision is used" variant. |
This comment has been minimized.
This comment has been minimized.
To be fair, Besides, |
This comment has been minimized.
This comment has been minimized.
And |
This comment has been minimized.
This comment has been minimized.
Undeveloped thought: pub fn to_dep_node(self, tcx: TyCtxt<'..>, kind: DepKind) -> DepNode;(By analogy to |
This comment has been minimized.
This comment has been minimized.
|
Hmm, this lint produces 1514 warnings on Servo's style component alone, and the fix looks a lot more verbose and ugly :( |
emilio
referenced this issue
Sep 23, 2018
Merged
Indicate the anonymous lifetime in Formatter. #1397
This comment has been minimized.
This comment has been minimized.
|
Most of them are actually unused lifetimes, as in, there's no relation with them and the output of the function... I think @eddyb's approach of only warning when elision actually comes at play it's way better than the current warning, getting the usefulness without the annoyance. |
This comment has been minimized.
This comment has been minimized.
|
@scottmcm I frankly disagree we need explicit lifetimes in that case. |
bors
added a commit
that referenced
this issue
Sep 30, 2018
bors
added a commit
that referenced
this issue
Sep 30, 2018
This comment has been minimized.
This comment has been minimized.
|
Here's a related pet peeve of mine. Currently, this compiles: struct Foo<'a>(&'a ());
impl Foo<'_> {} // anonymous lifetimeBut this doesn't: struct Foo<'a>(&'a ());
impl Foo {} // elided lifetimeSometimes requiring |
This comment has been minimized.
This comment has been minimized.
|
I wonder, would it be reasonable to stabilize only in-band lifetimes on functions (not methods)? AFAICT, there is no ambiguity about where those lifetimes come from, right? fn foo(x: &'a usize) -> &'a usize { ... } |
This comment has been minimized.
This comment has been minimized.
|
To be clear, I mean that we would stabilize a useful subset now as long as it is future-compatible with the rest of in-band lifetimes. |
This comment has been minimized.
This comment has been minimized.
|
I question whether partially adding such a feature simplifies anything,
since even if one believes leaving out lifetime declarations is a good
thing, we would actually be adding *more* rules about where that's allowed.
And it still makes situations like the following harder to read.
```
fn foo<'a>(_: &'a i32) {
fn bar<'a>(_: &'a i32) { }
fn baz(_: &'a i32) { }
}
```
…On Thu, Nov 15, 2018, 00:03 Who? Me?! ***@***.*** wrote:
To be clear, I mean that we would stabilize a useful subset now as long as
it is future-compatible with the rest of in-band lifetimes.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#44524 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAC3n4pn0YWVwjUEQRnvRBmsv9CrZenHks5uvPWjgaJpZM4PVFyw>
.
|
This comment has been minimized.
This comment has been minimized.
|
Hmm... I hadn't thought about nested functions... |
carols10cents
referenced this issue
Jan 3, 2019
Open
Update lifetimes to include anonymous lifetime syntax #1273
This comment has been minimized.
This comment has been minimized.
briansmith
commented
Feb 6, 2019
•
|
I came across this issue when converting my code to Rust 2018 edition. I have lots of code that elides lifetimes in parameters and the Initial code: pub struct S<'a>(&'a [u8]);
pub fn f(a: S) -> S { a }My understanding is that omitting the lifetime parameters like that is deprecated and pub fn f(a: S<'_>) -> S<'_> { a }However, then I generalized the initial code ( pub struct S<A: AsRef<[u8]>>(A);
pub fn f<A: AsRef<[u8]>>(a: S<A>) -> S<A> { a }When I run In general, Rust programmers need to be able to understand generic code and that means that they'll need to understand that there are potentially unseen lifetimes arguments implicitly in play when a reference type is used as the concrete type in a generic context. I think encouraging explicit lifetimes in non-generic contexts is only going to make it harder for people to understand this. Also, over the course of maintaining my "idiomatic" code, I found that the unnecessary-but-idiomatic explicit lifetimes actually resulted in bugs. See briansmith/ring#767 in particular. That bug wouldn't have occurred if I had used the old style of eliding the lifetime. Therefore, I think we shouldn't call the use of unnecessary (according to the compiler) explicit lifetimes "idiomatic". I hope this can be reconsidered before JetBrains CLion replaces its "elide lifetimes" quick-fix with what |
This comment has been minimized.
This comment has been minimized.
|
@briansmith The difference I see between those two is that |
This comment has been minimized.
This comment has been minimized.
|
Re-briansmith/ring#767 the new "idiomatic" way to write that signature is pub fn open_in_place<'a>(
key: &OpeningKey,
nonce: Nonce,
aad: Aad<'_>,
in_prefix_len: usize,
ciphertext_and_tag_modified_in_place: &'a mut [u8]
) -> Result<&'a mut [u8], Unspecified>which makes it explicit that the passed |
aturon commentedSep 12, 2017
•
edited by pnkfelix
This is a tracking issue for the RFC "In-band lifetime bindings" (rust-lang/rfcs#2115).
Steps:
'_(this has its own tracking issue, #48469)#15872: Enable elision in impl headers (mentoring instructions here)impl_header_lifetime_elisionin #15872'_in where-clauses on functions. -- blocked on #15872Unresolved questions:
'tcxand'gcxto be used consistentlyCan we find an unequivocally-better syntax than'_for elided lifetimes?Known bugs (possibly incomplete list):