const
" #222fn { mod { (use) super::...; } }
and its interaction with derive patterns" #193Please update these in https://github.com/orgs/rust-lang/projects/31/views/7.
scottmcm: I think I'm available this month.
NM: I'd like to talk about project goals.
Josh: +1. I'm happy to help put something together.
NM: I'd like to talk about the specific goals rather than the mechanism.
NM: I'd like to put out a public announcement and call for proposals on this to try to find owners.
Consensus: We'll schedule a special meeting for this:
TC: CE and I have been discussing this. He's interested in talking this over with the team.
NM/tmandry: We should talk about this. Maybe in May.
NM: Is this going to happen?
scottmcm: Could we just add the types and not language bits until Rust 2027?
Mara: What we still need is guidance for the library authors about what to do.
Mara: We cannot add a type if we cannot explain to the world how to use this.
Mara: We might want to discuss delaying the edition. Maybe we should have a Rust 2025 edition.
scottmcm: It'd be good for us to aggressively go through and punt things from the edition. (Delaying the edition for things will make 2027 also be a rush; if people know things get punted out it'll make it more likely they'll actually happen the year before next time.)
Consensus: We'll do edition review on the 10th.
TC: We accepted the RFC and the implementation has landed for Rust 2024. We do need to stabilize some way of expressing precise capturing. We're close to stabilizing ATPIT.
TC: However, in terms of timeline, landing TAIT is going to be tight (to the point of likely impossible). I'm going to write an RFC with a more direct means for precise capturing, e.g. using impl<'t, T> Trait
or impl('t, T) Trait
syntax. E.g.:
-> impl<'t, T> Trait'
-> impl<> Trait
We should discuss this as this work will need to start immediately to make the edition.
NM:
-> impl[] Trait
– technically unambiguous, I suppose :) ([T]
is not a trait)
fn foo<T>(&self, data: &Vec[T]) -> impl<T> Trait { ... }
(Discussion about "why can't we land TAIT ahead of the edition?")
TC: Landing TAIT in time is just going to be too tight and too much of a rush. No-one wants TAIT to land sooner than I do, and I'm still saying this, so that might be one reference point. It makes a lot of sense to land ATPIT first and to let that soak for 2-3 releases. The design axioms on which ATPIT were based were great (thanks NM) and led to a simpler and better design. There may well be lessons from those that we should carry over into the design of TAIT, but none of us are thinking hard about those at the moment because we're still trying to land ATPIT.
TC: The ATPIT stabilization is going well, but there are just a lot of little thingss to do, and we're waiting, e.g. on FCP periods to complete on the T-types side to solve various blockers. Even landing ATPIT ahead of Rust 2024 may be tight.
NM: I'm amenable to the idea of doubling down on ATPIT and doing this, then we can do TAIT in 2025.
TC: In talking with Oli, the feeling is that we need to start on this soon, as even landing this syntax will be tight before Rust 2024 when considering the lead time of the implementation, the various reviews, and the time for various FCPs on the types side.
NM: Timeline:
NM: It seems to me that the role of lang + types is fairly clear:
Can we then proceed with an experiment + bikeshed in parallel? It may also be useful to stabilize or pursue an impl that only supports the case where all type parameters are specified (since the compiler impl already has to deal with that).
TC: In terms of the semantics, for reference (and for why we don't want people to have to write this by hand), here's a desugaring prepared for the RFC:
// This is an example of how precise capturing syntax could be
// desugared to ATPIT.
#![feature(impl_trait_in_assoc_type)]
#![allow(unused)]
struct Ty<'u, U>(&'u (), U);
impl<'u, U> Ty<'u, U> {
// Equivalent to `-> impl<'u, 't, U, T> Sized`.
pub fn f<'t, T>(self, x: &'t (), y: T) -> <() as _0::H>::Opaque<'u, 't, U, T> {
<() as _0::H>::f(self, x, y)
}
}
mod _0 {
use super::*;
pub trait H {
type Opaque<'u, 't, U, T>;
fn f<'u, 't, U, T>(s: Ty<'u, U>, x: &'t (), y: T) -> Self::Opaque<'u, 't, U, T>;
}
impl H for () {
type Opaque<'u, 't, U, T> = impl Sized;
#[inline(always)]
fn f<'u, 't, U, T>(s: Ty<'u, U>, x: &'t (), y: T) -> Self::Opaque<'u, 't, U, T> {
(s, x, y)
}
}
}
fn main() {
let _ = Ty(&(), ()).f(&(), ());
}
Waffle: +1 on that plan.
NM: Also, this allows a much more straightforward migration than with TAIT.
Josh: Even if we could ship TAIT in two weeks, this is still something that we might want and that has value.
NM: +1. The bet before was that "maybe we'll want this, but maybe we could get away with just TAIT". So in many ways I feel good about just doing it.
tmandry: +1. Maybe we should just start the bikeshed now.
TC: +1. The main point of bikeshed is what character to use.
tmandry: My only concern on the angle bracket is that for impl
it's normally used to introduce a parameter.
Waffle: Angle brackets are used for introducing parameters and applying them to items. So it's not completely new for Rust. I see how it could be confusing, but I think it'd be fine.
NM: It's a really nice syntax. I almost hate to use it here, which I think will be obscure. I would prefer impl<'a>
being used to mean impl for<'a>
. So I have mixed feelings.
Nadri: If we had an explicit syntax for closure capture we could reuse it for type/lifetime capture.
tmandry: Of the options on the table… mixed feelings.
Josh: My feeling is that trying to use impl<'a>
as an alias for for<'a>
I think would be more confusing.
Josh: More broadly, I think this is actually consistent with our use of angle brackets and impl
.
tmandry: There is a sense in which it is consistent, but it depends where you put the weight.
pnkfelix: Maybe move(...) impl Trait
would actually make sense. (As in move('a, T) impl Trait
… since you're allowing the lifetime and type to propogate ("move") into the existentials.
NM: Relevant, my prior "explicit capture clause" for closure proposal: https://hackmd.io/@nikomatsakis/SyI0eMFXO, which was using move(a) ||
as the syntax.
NM: +1 to Nadri's point; it'd be nice if we could share syntax for this.
Nadri: The forall
understanding doesn't quite work because we can't add bounds like -> impl<T: Clone> Trait
.
NM: That's hopefully a temporary limitation.
Josh: Is there a + 'a
style syntax we could use.
NM: It means the wrong thing, something more like union than intersection.
TC: We could generalize the notion Josh is proposing here and have, e.g., additional syntax in the bound. E.g. impl Trait & 'a & T
or whatever to capture the notion of intersection rather than union (though these options seem bad in other ways, e.g. that we need a way to express "captures nothing" and this doesn't naturally provide that).
TC: +1 on sympathy to wanting a shared syntax for closure capturing.
pnkfelix: I don't hate using the use
keyword.
pnkfelix: If we use a new keyword, we may have more freedom about where it can be placed.
tmandry: While I'm mildly worried about the ambiguity, this isn't decisive for me.
As an idea, this could mean to capture everything, i.e. another way to express the default:
-> impl<..> Trait
-> impl<_> Trait
TC: Subject to us resolving this bikeshed, are we all +1 on this? That is, we're in favor of adding some syntax to solve this problem; we just need to work out what that syntax is exactly.
NM, tmandry, Josh, scottmcm, pnkfelix, TC: +1.
Consensus: Subject to resolving the bikeshed, we're all in favor of adding syntax for this purpose.
TC: Back to the bikeshed, let's write out all the options:
-> impl<'t, T> Trait //
-> impl('t, T) Trait //
-> impl['t, T] Trait //
-> impl Trait & 't & T //
-> impl use<'t, T> Trait //
-> impl captures<'t, T> Trait //
-> impl move<'t, T> Trait //
scottmcm: given Niko's earlier statement about letting impl<'a>
being impl for<'a>
potentially, my favourite (weakly) is something with a (probably contextual) keyword to be more specific about it being a capture list.
NM: Consider, e.g., these cases. The key point here is that it does NOT capture '_
:
fn foo<T>(&self, vec: Vec<T>) -> impl use<T> Display
fn foo<T>(&self, vec: Vec<T>) -> impl Display & T
fn foo<T>(&self, vec: Vec<T>) -> impl use<> Display
fn foo<T>(&self, vec: Vec<T>) -> impl Display & [] ?
pnkfelix: Trait & ['a, T]
would be clearer than Trait & 'a & T
, (not that I like either of those).
scottmcm: AsRef &T
and AsRef<&T>
being different feels really awkward.
tmandry: Can we "opt out" from a capture list? e.g. -X
to mean "doesn't capture X".
TC: I would expect to have a positive and negative form, so you can say impl<.., -X>
or something like that. But we could do that later, and we've never gotten around to doing this for imports with use
though there is a similar use case there.
TC: Let's survey our preferences:
Person | <> |
() |
[] |
& |
use<> |
captures<> |
move<> |
via<> |
---|---|---|---|---|---|---|---|---|
nikomatsakis | -1* | -1* | -1* | -1 | +1 ish | -0 | +0.5 | -0 |
joshtriplett | +1 | -1 | -0.5 | -1 | +0.5 | +0.9 | -1 | |
pnkfelix | +0.1 | +0.5 | +0 | -1 | +1 | +1 | +1 | |
tmandry | +0.75 | -0 | +0.5 | -1 | +0.75 | +0.75 | -1 | +0.5 |
TC | +0.5 | +0 | -0 | -1 | +1 | +0 | -0 | +0 |
waffle | +1 | +0 | -1 | -1 | -1 | -1 | -1 |
NM: The problem with captures
is that it's just too long. I want to use it on closure captures also, and it's just too long.
Josh: Aside from closure captures, how do you feel about it?
NM: I'll go -0
maybe. I like the clarity, but it just doesn't feel like Rust.
pnkfelix: Regarding the length complaint against "captures", perhapsimpl via<'a, T>
?
tmandry: Brainstorming about closure captures syntax:
let foo = String::from("hello");
let mut v = vec![];
let fun = move(foo.clone()) || { ... };
let fun = use(foo.clone()) || { ... };
let fun = captures(foo.clone()) || { ... };
TC: For closures there are the values that we capture, but there's also the capturing of the outer type and lifetime parameters. We often don't want to capture all of those. This comes up also for async
blocks, and it will come up for gen
, async gen
, async closures, gen
closures, async gen
closures, etc. also.
NM: moving to -1 on <>
because of TC's point that we may want to limit type capture for closures, async blocks, async generators, genreators, etc. etc. etc. and I don't see how the <>
syntax will scale to that. (On same point, not sure it will always want to be contextual.)
TC: This has been helpful. It seems that if possible we want something that aligns with what we might want to do for closure-like blocks. I'll write something up. We'll try to get an experiment going in parallel.
(The meeting ended here.)
Link: https://github.com/rust-lang/lang-team/issues/21
Link: https://github.com/rust-lang/lang-team/issues/22
Link: https://github.com/rust-lang/lang-team/issues/51
Link: https://github.com/rust-lang/lang-team/issues/88
Link: https://github.com/rust-lang/lang-team/issues/137
Link: https://github.com/rust-lang/lang-team/issues/149
None.
i128
/u128
from the improper_ctypes
lint" lang-team#255Link: https://github.com/rust-lang/lang-team/issues/255
const {}
blocks, and const { assert!(...) }
" lang-team#251Link: https://github.com/rust-lang/lang-team/issues/251
Link: https://github.com/rust-lang/lang-team/issues/21
Link: https://github.com/rust-lang/lang-team/issues/22
Link: https://github.com/rust-lang/lang-team/issues/48
Link: https://github.com/rust-lang/lang-team/issues/51
Link: https://github.com/rust-lang/lang-team/issues/54
Link: https://github.com/rust-lang/lang-team/issues/80
Link: https://github.com/rust-lang/lang-team/issues/87
Link: https://github.com/rust-lang/lang-team/issues/88
Link: https://github.com/rust-lang/lang-team/issues/123
Link: https://github.com/rust-lang/lang-team/issues/137
Link: https://github.com/rust-lang/lang-team/issues/149
Link: https://github.com/rust-lang/lang-team/issues/172
Link: https://github.com/rust-lang/lang-team/issues/185
Link: https://github.com/rust-lang/lang-team/issues/186
fn { mod { (use) super::...; } }
and its interaction with derive patterns" lang-team#193Link: https://github.com/rust-lang/lang-team/issues/193
Link: https://github.com/rust-lang/lang-team/issues/199
Link: https://github.com/rust-lang/lang-team/issues/221
const
" lang-team#222Link: https://github.com/rust-lang/lang-team/issues/222
Link: https://github.com/rust-lang/lang-team/issues/229
Link: https://github.com/rust-lang/lang-team/issues/232
Link: https://github.com/rust-lang/lang-team/pull/236
Link: https://github.com/rust-lang/lang-team/pull/237
Link: https://github.com/rust-lang/lang-team/issues/244
Link: https://github.com/rust-lang/lang-team/issues/245
Link: https://github.com/rust-lang/lang-team/pull/258
Link: https://github.com/rust-lang/lang-team/issues/259