You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Naming: these were originally named fill, fill_with, and fill_from to be consistent consistent with slice::{fill_with,fill_from}. Since changing to slice-inherent methods, these needed to be renamed to avoid conflict. Should we change to naming that keeps fill? Amanieu suggested fill_init at Add inherent versions of MaybeUninit methods for slices #129259 (comment).
I'm not planning to implement a <T: Clone>(&mut [MaybeUninit<T>], T) -> &mut [T] function as part of this feature, though I think it would be fine for someone else to do so if they have a view on what the correct Drop semantics should be.
Alternatively, maybe a -> &mut [ManuallyDrop<T>] would work for your use case? That would be safe to add since it makes the special-ness clear.
@python-ast-person If I understand you correctly, then you'd use the proposed fill_cloned to implement in-place construction of a Box<[T]> like this (playground link):
// presumed to exist as part of unsized MaybeUninitimpl<T>MaybeUninit<T>{fntranspose_slice<'a>(this:&'amutMaybeUninit<[T]>) -> &'amut[MaybeUninit<T>]{unimplemented!()}}fnmake_box<T: ?Sized>(size: <TasPointee>::Metadata,filler:implFnOnce(&mutMaybeUninit<T>) -> &mutT,) -> Box<T>{unimplemented!()}fnmain(){let boxed = make_box::<[String]>(10, |u:&mutMaybeUninit<[String]>| {let a = String::from("a");let transposed = MaybeUninit::transpose_slice(u);MaybeUninit::fill_cloned(transposed,&a);unsafe{MaybeUninit::slice_assume_init_mut(transposed)}});println!("boxed: {boxed:?}");}
Having MaybeUninit::fill_cloned() return a &mut [T] would provide only slightly cleaner code (one less line).
If you want construction of Box<[T]> to be possible without any unsafe at all, then you might want a helper function that takes ownership of its input, which should be Drop-safe. This can't be part of MaybeUninit directly because Box isn't available in the core crate, but it should be straightforward to implement if you already have unsized MaybeUninit in your codebase.
// internally does fill_cloned + slice_assume_init_mut() as abovefnfill_box_cloned<T:Clone>(this:Box<MaybeUninit<[T]>>,value:&T) -> Box<[T]>;
One, I suggest that fill_from returns -> (&'a mut [T], &'a mut [MaybeUninit]) where the second slice is the uninitialized remainder. This produces a more useful API while harmless to anyone who doesn't want that remainder- they can just throw it away.
Another thing: I disagree that having fill_cloned should return an immutable reference. The &mut [T] returned from fill_cloned will already cause the destructors to be leaked regardless of mutability, or regardless of whether new values are written into the mutable slice. I don't know of any other method in std which takes a mutable reference and returns an immutable reference to the safe object and, in my opinion, should only be used where necessary to prevent true safety issues.
A box version was in my original proposal. I removed it due to a suggestion referring to rust-lang/rfcs#2884. Perhaps these two things should coexist, however.
It might be useful for fill_with's F to accept an index:
pubfnfill_with<'a,F>(this:&'amut[MaybeUninit<T>],f:F) -> &'a[T]whereF:FnMut(usize) -> T;// <-- accepts an index (current element that is being written to)
Alternatively, you could just store and mutate a counter inside the passed in closure, but this might be more convenient...
Having the same interface for Box needs a new ACP. I agree that it would be useful in some cirucumstances. Also, if you are going to make such an ACP, note that fill_cloned is not necessary due to specialization. See the implementation of the slice’s fill.
re: the function accepting an index. This is a different API from the slice’s fill_with method. Ideally MaybeUninit slice APIs mirror the slice APIs, especially if occupying the same name. Loading your closure with index state is trivial, and any use case that doesn’t want the index will have to throw it away.
I think the confusion here is simply the outdated OP issue description. I was under the impression that the API design written above was the most recent one but as ajwock mentioned below, the preference is to use specialization to avoid having both fill and fill_cloned which makes total sense. It would be great if someone could update the issue description though, just to help future readers :)
I think fill_with should take a closure with one parameter, containing the index to be filled. That would allow the user to do different things depending on that. Compare array::from_fn.
I think fill_with should take a closure with one parameter, containing the index to be filled. That would allow the user to do different things depending on that. Compare array::from_fn.
Yeah, came here to say the same. Unfortunately slice::fill_with is already stable and does not take an index.
@tgross35 I am confused by your edits to the tracking issue. Is there a PR that renames fill to write_filled etc? There is none linked above that I could find, and the current nightly still has fill.
That is in #135394, I updated this with the assumption that the change would go through reasonably quick. I'll change it back for now and nominate the PR.
For the write_with and write_iter methods, I think it is important to document that the values in the original MaybeUninit array need to be manually dropped later. Alternatively, we could implement a transparent wrapper which will drop it when it goes out of scope and which implements DerefMut for the slice. I believe one of these should be done, and the choice is whether we want to require the user to manually drop it.
I believe the better option is to create a wrapping structure. This is because it will allow users to avoid unsafe code. In its current state, using write_iter does not always avoid unsafe, because the user might need to drop it, in which case they currently need to use assume_init_drop. Also, writing a wrapping structure means we can implement methods that will take ownership of the elements, which write_iter currently can't do. For example, we could implement IntoIterator on the wrapping structure.
I've had the same thought, though admittedly I personally did not have the use case myself and I implemented that in response to the same concerns you had. I'll go ahead and publish that as a crate as the libs-team suggested. Perhaps it will find some use if it is made available.
fill_with was mentionned to me for a problem i was tryng to solve, but it turned out to not be good enough, so i'd like it to be mentionned at least even if my fix also has its flaws.
i believe that fill_with should take a FnMut(&mut [T]) -> T, as allowing lookback during the creation of the elements.
i can understand how it could be too clunky, and is not how things like array::from_fn work
Activity
jmillikin commentedon Nov 1, 2023
#80376
If a
&mut [T]is returned forT: Clone, there's no indication to downstream code that writing values to that slice will cause them to leak.jmillikin commentedon Nov 15, 2023
I'm not planning to implement a
<T: Clone>(&mut [MaybeUninit<T>], T) -> &mut [T]function as part of this feature, though I think it would be fine for someone else to do so if they have a view on what the correctDropsemantics should be.Alternatively, maybe a
-> &mut [ManuallyDrop<T>]would work for your use case? That would be safe to add since it makes the special-ness clear.jmillikin commentedon Nov 24, 2023
@python-ast-person If I understand you correctly, then you'd use the proposed
fill_clonedto implement in-place construction of aBox<[T]>like this (playground link):Having
MaybeUninit::fill_cloned()return a&mut [T]would provide only slightly cleaner code (one less line).If you want construction of
Box<[T]>to be possible without anyunsafeat all, then you might want a helper function that takes ownership of its input, which should beDrop-safe. This can't be part ofMaybeUninitdirectly becauseBoxisn't available in thecorecrate, but it should be straightforward to implement if you already have unsizedMaybeUninitin your codebase.ajwock commentedon Feb 17, 2024
Hey, a couple of opinions on the API here.
One, I suggest that fill_from returns -> (&'a mut [T], &'a mut [MaybeUninit]) where the second slice is the uninitialized remainder. This produces a more useful API while harmless to anyone who doesn't want that remainder- they can just throw it away.
Another thing: I disagree that having fill_cloned should return an immutable reference. The &mut [T] returned from fill_cloned will already cause the destructors to be leaked regardless of mutability, or regardless of whether new values are written into the mutable slice. I don't know of any other method in std which takes a mutable reference and returns an immutable reference to the safe object and, in my opinion, should only be used where necessary to prevent true safety issues.
A box version was in my original proposal. I removed it due to a suggestion referring to rust-lang/rfcs#2884. Perhaps these two things should coexist, however.
ajwock commentedon Feb 18, 2024
jmillikin has allowed me to take over implementation: #121280
ajwock commentedon Feb 20, 2024
rust-lang/libs-team#338
This idea is my response to the (legitimate) criticism of these APIs that they could lead to destructor leaks.
cynecx commentedon Feb 23, 2024
It would've been nice to also have the "same" interface for boxed slices:
Does this need a new ACP or would it be possible to also consider this under
maybe_uninit_fill?cynecx commentedon Feb 23, 2024
It might be useful for
fill_with'sFto accept an index:Alternatively, you could just store and mutate a counter inside the passed in closure, but this might be more convenient...
ajwock commentedon Feb 27, 2024
Having the same interface for Box needs a new ACP. I agree that it would be useful in some cirucumstances. Also, if you are going to make such an ACP, note that
fill_clonedis not necessary due to specialization. See the implementation of the slice’sfill.re: the function accepting an index. This is a different API from the slice’s
fill_withmethod. Ideally MaybeUninit slice APIs mirror the slice APIs, especially if occupying the same name. Loading your closure with index state is trivial, and any use case that doesn’t want the index will have to throw it away.cynecx commentedon Feb 27, 2024
Hmm, those are quite "different" APIs. Slice's fill and co doesn't allow a fully safe way to initialize a boxed slice.
Not sure if that's the one you mentioned, but I've looked through several places and I can't seem to find a similar api:
EDIT (To reduce additional noise here):
I think the confusion here is simply the outdated OP issue description. I was under the impression that the API design written above was the most recent one but as ajwock mentioned below, the preference is to use specialization to avoid having both
fillandfill_clonedwhich makes total sense. It would be great if someone could update the issue description though, just to help future readers :)1 remaining item
Rua commentedon Jun 6, 2024
I think
fill_withshould take a closure with one parameter, containing the index to be filled. That would allow the user to do different things depending on that. Comparearray::from_fn.RalfJung commentedon Feb 21, 2025
Yeah, came here to say the same. Unfortunately
slice::fill_withis already stable and does not take an index.RalfJung commentedon Feb 21, 2025
@tgross35 I am confused by your edits to the tracking issue. Is there a PR that renames
filltowrite_filledetc? There is none linked above that I could find, and the current nightly still hasfill.tgross35 commentedon Feb 21, 2025
That is in #135394, I updated this with the assumption that the change would go through reasonably quick. I'll change it back for now and nominate the PR.
Rollup merge of rust-lang#135394 - clarfonthey:uninit-slices-part-2, …
Unrolled build for rust-lang#135394
Rollup merge of rust-lang#135394 - clarfonthey:uninit-slices-part-2, …
ljtpetersen commentedon Jun 30, 2025
For the
write_withandwrite_itermethods, I think it is important to document that the values in the originalMaybeUninitarray need to be manually dropped later. Alternatively, we could implement a transparent wrapper which will drop it when it goes out of scope and which implementsDerefMutfor the slice. I believe one of these should be done, and the choice is whether we want to require the user to manually drop it.I believe the better option is to create a wrapping structure. This is because it will allow users to avoid unsafe code. In its current state, using
write_iterdoes not always avoid unsafe, because the user might need to drop it, in which case they currently need to useassume_init_drop. Also, writing a wrapping structure means we can implement methods that will take ownership of the elements, whichwrite_itercurrently can't do. For example, we could implementIntoIteratoron the wrapping structure.Something like
I am willing to implement this if we want to go with it, since I find it interesting. Though, I don't know how contribution works for the std lib.
ajwock commentedon Jun 30, 2025
rust-lang/libs-team#338
I've had the same thought, though admittedly I personally did not have the use case myself and I implemented that in response to the same concerns you had. I'll go ahead and publish that as a crate as the libs-team suggested. Perhaps it will find some use if it is made available.
Morgane55440 commentedon Apr 1, 2026
fill_withwas mentionned to me for a problem i was tryng to solve, but it turned out to not be good enough, so i'd like it to be mentionned at least even if my fix also has its flaws.i believe that
fill_withshould take aFnMut(&mut [T]) -> T, as allowing lookback during the creation of the elements.i can understand how it could be too clunky, and is not how things like
array::from_fnworkRollup merge of rust-lang#160432 - joboet:ensure_init_generic, r=clar…
Unrolled build for #160432
Rollup merge of #160432 - joboet:ensure_init_generic, r=clarfonthey