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 upAnonymous/placeholder lifetime "'_". #1177
Conversation
eddyb
referenced this pull request
Jun 26, 2015
Merged
rustc: use methods instead of functions in middle::ty. #26575
This comment has been minimized.
This comment has been minimized.
erickt
commented
Jun 26, 2015
This comment has been minimized.
This comment has been minimized.
|
I think we could make |
P1start
reviewed
Jun 27, 2015
|
|
||
| # Detailed design | ||
|
|
||
| In `resolve_lifetime`: if the lifetime to be resolved matches "'_", store |
This comment has been minimized.
This comment has been minimized.
P1start
Jun 27, 2015
Contributor
"'_" should be in backticks so GitHub doesn’t render the text after it italicised.
P1start
reviewed
Jun 27, 2015
| Small caveat: this check has to be done only if the lifetime has not been | ||
| already resolved, because `'_` is a legal lifetime in stable Rust, e.g.: | ||
| ```rust | ||
| fn foo<'a, T>(xs: &'_ [T]) -> &'_ T { &xs[0] } |
This comment has been minimized.
This comment has been minimized.
eddyb
force-pushed the
eddyb:lt-anon
branch
from
59f3fd3
to
fbf5eef
Jun 27, 2015
This comment has been minimized.
This comment has been minimized.
bluss
commented
Jun 27, 2015
|
Removing existing I've wanted this feature, tried to use it only to find it didn't exist. |
nikomatsakis
added
the
T-lang
label
Jun 29, 2015
This comment has been minimized.
This comment has been minimized.
|
I'm in favor of the general idea of this RFC, but I think I'd prefer a slightly more expanded version to make things more uniform. Basically So what this means is that: In a fn signature:
In fn body:
In a type definition or other context:
Besides being more uniform, this also offers a nice compromise with respect to lifetime elision. I sometimes find if I have a signature like this: struct Iter<'collection> { ... }
fn iter(&self) -> Iter { ... }it is very pretty but not as explicit as I might like, as there is no signal (outside of the type definition) that the borrow will be extended when the fn returns to cover the return value. Still, naming the lifetime seems like overkill: fn iter<'a>(&'a self) -> Iter<'a> { ... }I'd be happy with a version that uses fn iter(&self) -> Iter<'_> { ... }This tells me that the borrow will be extended, but avoids the need to give a name. |
This comment has been minimized.
This comment has been minimized.
|
Independent from this RFC, we should fix the bug about |
This comment has been minimized.
This comment has been minimized.
|
Marking this as T-lang: cc @rust-lang/lang |
This comment has been minimized.
This comment has been minimized.
Speaking of extensions,
|
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis the problem with making
expand to
I.e., it is not clear from the syntax if multiple uses represent one fresh variable or many fresh variables. I guess we have this problem with elision already, but some how representing the elided lifetimes with |
This comment has been minimized.
This comment has been minimized.
|
@nrc AFAICT, elision is not necessary for any of the planned uses. |
This comment has been minimized.
This comment has been minimized.
|
@eddyb well, it seems like the hypothetical confusion described by @nrc would arise under the planned uses... i'm thinking in particular of a case like: struct Context<'a, 'left: 'a, 'right: 'a, 'd> {
left: &'a Inner<'left>,
right: &'a Inner<'right>,
data: &'d str,
}
fn neither<'data>(cx: Context<'_, '_, '_, 'data>) -> &'data str {
cx.data
}where it sounds like @nrc is worried that people will interpret the above as injecting a single fresh lifetime and then constraining the first three lifetime parameters to (Having said that, I do not think we should worry too much about such misunderstandings.) |
This comment has been minimized.
This comment has been minimized.
|
@nrc I see your point about potential confusion, but I think that having |
This comment has been minimized.
This comment has been minimized.
|
Did a quick grep across crates.io (thanks, @brson sxd-xpath-0.1.1/src/function.rs: fn pop_value_or_context_node<'_>(&mut self, context: &EvaluationContext<'_, 'd>) -> Value<'d> {
sxd-xpath-0.1.1/src/function.rs: fn pop_nodeset_or_context_node<'_>(&mut self, context: &EvaluationContext<'_, 'd>)
term_grid-0.1.1/src/lib.rs:impl<'_> convert::From<&'_ str> for Cell {
term_grid-0.1.1/src/lib.rs: fn from(string: &'_ str) -> Self {I honestly didn't expect anyone to use Now, the way this RFC is phrased right now (and the initial implementation) would let those cases compile, with the same semantics as before, regardless of the feature gate. |
This comment has been minimized.
This comment has been minimized.
The reason why at least some people use it is actually quite interesting - lifetimes |
eddyb
referenced this pull request
Jul 13, 2015
Closed
RFC for allowing eliding more type parameters. #1196
This comment has been minimized.
This comment has been minimized.
|
Seems like conversation has stalled here. My current feeling is unchanged: I am in my favor if we make There is one interesting corner case: I think that That last part would mean that |
nikomatsakis
self-assigned this
Jul 16, 2015
This comment has been minimized.
This comment has been minimized.
|
So we just discussed this RFC in a recent lang team meeting. The consensus was that we are not ready to move it to FCP. The current text (which assigns fresh lifetimes everywhere) isn't optimal. There was some discussion about what semantics to use. The primary contenders are:
The only real point where these proposals differ is on the semantics of
I still favor the third proposal, because, well, because it does what I expect in all cases. It means that There was agreement that using |
This comment has been minimized.
This comment has been minimized.
|
Note: it's worth pointing out that if we did adopt this RFC --- particularly with a lint --- we would probably want to wait until support for |
This comment has been minimized.
This comment has been minimized.
|
Further thoughts: I think we should move the question of a lint to a separate RFC, since it's a major stylistic adjustment, particularly my (now) preferred version, which only allows eliding lifetimes from |
This comment has been minimized.
This comment has been minimized.
|
(Note though that if we adopted this version of the lint, then the third alternative ( |
This comment has been minimized.
This comment has been minimized.
|
Talking with @wycats we were thinking that
It does seem like finding something less RSI-inducing than |
This comment has been minimized.
This comment has been minimized.
|
I really like the idea of a mechanism for expressing "there is a ref here" without the need to juggle the exact lifetimes. The lack of such a mechanism was part of the reason that we couldn't "go all the way" with lifetime elision (on structs), which was unfortunate in my opinion. I worry that |
This comment has been minimized.
This comment has been minimized.
aidancully
commented
Jul 18, 2015
|
This probably requires more thought, but... any reason not to just use |
This comment has been minimized.
This comment has been minimized.
|
@aidancully Wouldn't that conflict with the same syntax used for types? |
This comment has been minimized.
This comment has been minimized.
|
On Sat, Jul 18, 2015 at 09:22:26AM -0700, Felix S Klock II wrote:
I do not regard that as the same as an elided lifetime, no, and I would want |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis maybe this gets at the heart of my problem; if the absent lifetime in |
This comment has been minimized.
This comment has been minimized.
I agree this is a key question. The way I see it, in the language today, you can break down lifetimes into two categories: "explicit" lifetimes and "defaulted" lifetimes (perhaps we need better names):
The behavior when these lifetimes are elided is already different, and I think the intuition for the difference is that, with explicit lifetimes, the normal thing is for there to be borrowed data present, whereas for defaulted lifetimes, we want to generally say that there is no borrowed data (i.e., a So, for example, in type signatures:
In fn arguments, the behavior is similar. For explicit lifetimes, we default to a fresh lifetime, but for defaulted lifetimes, we prefer All of this seems consistent to me with us saying that defaulted lifetimes are not expected to have region data -- we expect objects not to close over region data. If you want otherwise, you have to ask for it, either by having a Now this is where Now, as for the lint I've been tossing about: my concern is that, in practice, people may forget (or never have known) that structs were defined with lifetime parameters, and so they may not realize where region data is hiding. For example, I think that when you read a type like As a concrete example, I sometimes write functions in the compiler like: fn foo<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty) { ... }which looks fine, unless you remember that UPDATE: Lightly edited for clarity. |
This comment has been minimized.
This comment has been minimized.
This was important for me to understand your POV. I think making this intuition part of a user's mental model is important, so anything we can do to pick names that encourage such an intuition will make things better. So, yes, we definitely need better names than "elided" and "defaulted". :) |
This comment has been minimized.
This comment has been minimized.
|
having said that, now I that I better understand the reasoning behind your POV, I retract my (here unstated, I think) objection to the suggested semantics for |
pnkfelix
referenced this pull request
Jul 28, 2015
Merged
The Advanced Rust Programming Language #27032
This comment has been minimized.
This comment has been minimized.
|
(Note, current status is: the lang team has basic consensus around this RFC, but is waiting for the RFC itself to be updated accordingly.) |
nikomatsakis
referenced this pull request
Sep 11, 2015
Closed
'missing lifetime specifier' regression in protobuf-1.0.1 #27248
alexcrichton
referenced this pull request
Sep 28, 2015
Closed
Allow using an undeclared '_ as an anonymous input or inference region. #26598
nikomatsakis
referenced this pull request
Oct 1, 2015
Open
Interaction between elision and trait objects is not ideal #1302
This comment has been minimized.
This comment has been minimized.
|
So @eddyb and I touched base on this, and we also discussed in @rust-lang/lang meeting. I am thinking of closing this RFC for the time being. For me, the TL;DR is that this RFC doesn't go far enough -- it can get us a small improvement over the status quo for complex lifetime scenarios (such as the compiler), but I want an "order of magnitude" improvement. And I think we can get one. Moreover, the secondary goal of the RFC -- or at least an effect of the RFC, if not an original goal -- was to help make elision more explicit, and in particular to help make the case where a lifetime is "hidden" in the return type more explicit, without requiring an explicit name. The RFC achieves that too, but it does it with a syntax that nobody is thrilled about, and may not go far enough in this direction. (e.g., @wycats has had some thoughts about having some notation that indicates "elided lifetimes here", but doesn't require you to indicate how many) For the time being, the hope is that we can keep progress in the compiler by moving away from free functions and towards methods, which tend to reduce "lifetime clutter" by moving the declarations up to the impl. @eddyb has been experimenting here. Now, in terms of getting a 10x win, I don't want to claim a complete plan. But I think we should explore some more advanced ideas. One thing that I've been kicking around -- and hope to produce a blog post or something about -- is adding lifetime-parameterized modules (essentially, a limited and specialized form of ML functors). The rough idea is that one would be able to add lifetime parameters to modules: mod with_ctxt<'tcx> { ... /* most of the compiler goes here */ ... }The intution for this is "all code in this module runs in the context of some lifetime When you refer to types in the module Obviously this is not even a pre-RFC. It's just a sketch of an idea that I think is worth pursuing. I feel though that there is a "min-max" proposal waiting to emerge here that might not be that hard to implement and could mean a massive ergonomic improvement. (Of course, any such efforts this would be very much an active experiment, with the compiler as the laboratory. It's clear though that there are "scalability" issues that arise with trying to use arenas at scale, and the compiler is a big consumer, so it's a good place to do such experiments.) Another possibility for improvements is leveraging associated lifetimes, which have never been implemented (and indeed, probably a new RFC would be needed for some parts of them, since I think the original associated items RFC had some gaps. For example, it did not discuss projection syntax like The rough idea here would be that one could define a trait that "bundles up" a number of lifetimes and their relationships: trait Tcx {
lifetime 'tcx;
}
struct TcxArenas<'tcx> {
ty_arena: &'tcx TypedArena<Ty<'tcx>>
...
}
impl<'tcx> Tcx for TcxArenas<'tcx> {
lifetime 'tcx = 'tcx;
}
struct Ty<T: Tcx> { ... }
struct Substs<T: Tcx> { ... }thus one would write |
This comment has been minimized.
This comment has been minimized.
|
That said, while writing that, I started to wonder if it wouldn't be worth adding |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis Using methods instead of free functions is not a panacea, but it goes a long way, enough to make this RFC quite underwhelming. |
eddyb
closed this
Mar 25, 2016
eddyb
deleted the
eddyb:lt-anon
branch
Mar 25, 2016
This comment has been minimized.
This comment has been minimized.
|
Still makes sense to issue a future compatibility warning for lifetimes named |
This comment has been minimized.
This comment has been minimized.
|
As an example of what can be done right now with impls: struct TyCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(&'a &'tcx &'gcx ());
#[allow(bad_style)]
struct module;
impl<'a, 'gcx, 'tcx> module {
fn foo(_: TyCtxt<'a, 'gcx, 'tcx>) {}
}
module::foo(TyCtxt(&&&()))Someone could turn this into a macro if they wanted to, and I haven't really abused it yet, but this flexibility of |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis re lifetime-parametric modules - I would love to have this, I've wanted it for ages. See, although there is not much there in the way of details #424. We should discuss... |
This comment has been minimized.
This comment has been minimized.
|
@petrochenkov we really should deprecate |
nrc
added
the
I-nominated
label
May 2, 2016
This comment has been minimized.
This comment has been minimized.
|
Nominated for discussion at the lang meeting - I want to talk about salvaging some bits of this RFC |
eddyb commentedJun 26, 2015
Initial implementation available at rust-lang/rust#26598.