-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Tracking issue for unsized tuple coercion #42877
Comments
Triage: no changes |
T-lang discussed this in a backlog bonanza meeting today, and noted several concerns that should be addressed prior to moving forward:
|
I subscribed to this because I wanted to use it once... but didn't because it's unstable and not too hard to work around. I suspect the same goes for many non-trivial projects. Searching GitHub shows 1391 code results, most of which appear to be tests. There are a few uses on the first page: https://github.com/aschaeffer/inexor-rgf-application, https://github.com/aschaeffer/rust-ecs-poc, https://github.com/libdither/disp, https://github.com/icostin/halfbit (feature = "nightly"); everything after that appears to be tests (I checked 10 more pages). In short: some possible utility, but not a priority. |
I wish to use this in safina-executor library. The library currently uses this type for async tasks: Arc<Mutex<dyn Future<Output = ()> + Send + Unpin>> I am modifying it to remember when a task has returned I would like to use the following type, but it depends on this Arc<Mutex<(bool, dyn Future<Output = ()> + Send + Unpin)>> Instead, I will use this type, which requires two allocations per task: Arc<Mutex<Option<Box<dyn Future<Output = ()> + Send + Unpin>>>> This is OK. Async tasks are generally long-lived data structures. Therefore, the extra allocation is a very small added cost. This |
To use |
@SimonSapin A struct works! struct Task<T: ?Sized> {
completed: bool,
fut: T,
}
impl<T> Task<T> {
pub fn new(fut: T) -> Arc<Mutex<Self>> {
Arc::new(Mutex::new(Task {
completed: false,
fut,
}))
}
}
impl Executor {
//...
pub fn spawn_unpin(self: &Arc<Self>, fut: impl (Future<Output = ()>) + Send + Unpin + 'static) {
let task = Task::new(fut);
let weak_self = Arc::downgrade(self);
self.async_pool.schedule(move || poll_task(task, weak_self));
}
} I think I'm going to keep the enum Task<T: ?Sized> {
None,
Some(T),
}
// error[E0277]: the size for values of type `T` cannot be known at compilation time |
I just realized that the |
There's an argument to be made for consistency. You can unsize coerce, deconstruct, and otherwise match against custom tuple types already. You can also do all these things on stable with built-in tuples too, given a touch of Footnotes
|
@QuineDot no you can't. You are merely using references to unsized types. However, this edited version works (avoids deconstruction of the unsized parameter, or more precisely merely avoids creating a |
@rustbot label +I-lang-nominated We discussed this some in the Rust-for-Linux sync meeting. This is impacting stabilization of It's also a 2-way door, of course, we can always add it back. Nominating to give lang a heads up about this. |
I think the feature should exist but I don't see a reason to prioritize it. Removing it to unblock higher priority work is fine with me. |
We cannot, though. Once |
I also don't think this feature really pulls its own weight. For structs, you are only forced to lay out the last field at the end when the last field is a generic parameter that is Besides, unsizing tuples has seen basically no use since it was added in 2017. It seems unlikely that anyone will push this to be stabilized any time soon. |
I tend to agree that we've been doing fine without tuple unsizing; unsized types aren't even that common and defining your own ADT for them isn't an undue burden -- given, as you say, that this unlocks more layout optimizations for tuples. However, we could want other unstable unsizing coercions in the future, and it seems we are closing the door for that. |
Niko mentioned in the meeting that this approach might be able to unblock future unstable impls. Though I tend to agree with CE's point that keeping around logic for doing unstable impls in one place and having various extra complexity to avoid leaking it seems like a bad state to be in. |
Remove unsizing coercions for tuples See rust-lang#42877 (comment) and below comments for justification. Tracking issue: rust-lang#42877 Fixes: rust-lang#135217
I am in favor of just removing this feature. Tuple unsizing coercions inhibits future layout optimizations for tuples: The last field of tuples would always have to be last in the actual layout as any tuple may participate in unsizing. // the actual layout of the tuple must not be `(u16, u16, u32)` as (u16, u32, dyn Send)`
// needs `dyn Send` to be at the end of the tuple.
let x: &(u16, u32, u16) = &(1, 2, 1);
let y: &(u16, u32, dyn Send) = x; This is not necessary for size optimizations as that optimization can always keep the last field in place; it doesn't matter where in the struct we pair values with matching alignment. It would inhibit other optimizations, e.g. @m-ou-se mentioned
It may also inhibit optimizations based on the "preferred alignment". For struct unsizing this only inhibits these optimizations for structs which can be unsized (have a |
This is a part of #18469. This is currently feature-gated behind
#![feature(unsized_tuple_coercion)]
to avoid insta-stability.Related issues/PRs: #18469, #32702, #34451, #37685, #42527
This is needed for unsizing the last field in a tuple:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=5f93d1d7c6ee0e969df53c13e1aa941a
The text was updated successfully, but these errors were encountered: