Change:
The description of : states that it "creates a draining iterator", leading to expectations that each iteration drains one element, that stopping the iteration should drain fewer elements because iterators are lazy (witnessed in ). The rest of the description counters that expectation, but by saying "when the iterator is dropped", there's again the suggestion that removal happens at that late stage. While conceptually it's simpler to state that the removal happens unconditionally and immediately, which corresponds to the verb "drain", like and do. says "unspecified how many elements are removed" if you circumvent dropping, which suggests it's only removing elements in the range like the rest of the text, but in reality the whole vector is slaughtered ( clarified one aspect of this case but slightly muddled this one). lists the possibility to use as if that is just one of the ways to use the iterator, which makes the description harder to understand if you're not advanced in Rust. does not say what happens to the elements removed but not yielded if the iterator is dropped before it is fully consumed. It makes most sense that they get dropped rather than leaked, but given what leeway grants itself elsewhere, it might be helpful to clarify. None of the other methods say this either (). also doesn't but I believe the fact that the signature says it consumes the container implies it. has the same issue (and got missed by ). probably too, it doesn't mention what may happen if you mem::forget the iterator. label A-collections A-docs C-enhancement T-libs-api
Follow-up to my remark and question here: I feel like "creates a draining iterator" does more accurately describe the situation. On second thought, and looking at the existing documentation you linked, I do actually agree that those are easier to understand. The tracking issue you link is quite long, so I don't feel like reading through all of it, but I would be interested if you could point out (some of) the concrete comments you're referring to where you witnessed any particular incorrect expectations. Maybe the best solution could be the high-level "Removes the specified range from the vector, returning all removed elements as an iterator"-style documentation in combination with an additional remark later in the documentation that explains why the iterator does nonetheless keep a mutable borrow on the original data-structure for the duration of its existence. So feel free to ignore this point in your PRs if you want, if I come up with a good way of phrasing such an additional remark, I can make a follow-up PR later.
That seems like a non-issue to me. Conventionally, dropping one thing should never result in leakage of a different thing, unless (that's explicitly documented). To quote myself in a different reply in your PR: <hrThis doesn't mean that I dislike your changes that explicitly call out the dropping, it doesn't hurt to be more explicit, I'm just saying the status quo is less imprecise that you might have assumed.
It starts even earlier than I thought: e.g. and lead to The currently most clearly lists the expectation. I feel this is due to the wording of "draining iterator". Good point.
For my 3rd bullet, I think it's imprecise (I'd use vague) because leaking is listed as one of the normal ways to use the iterator.
For clarity, I'm not claiming with any authority that does not do drain-on-drop. I'm saying its description (contract, design) does not require it to do anything on drop, apart from dropping unconsumed items and a vector buffer just like any . The fact it (currently) takes a mutable borrow, allows it to do something more on drop, suggests that it does something more on drop, and the current implementation indeed does something more on drop, but what it does is hardly draining but rather patching the vector internals and returning their ownership to the vector itself. The implementation could be changed to not need the borrow at all, at the cost of an allocation (just not sure if the stable signature could be changed to remove the mutable borrow in a compatible way). I think it's a stretch to call this drain-on-drop but who knows what the term actually stands for. My proposed is definitely not drain-on-drop by any standard, it doesn't need a mutable borrow (because a tree is split up in nodes whereas a vector has a single huge buffer).
Interesting… maybe I should at some point take the time to actually look through that discussion in the tracking issue. There’s a lot of topics being discussed a once though. Leaking should never be a normal way to use the iterator. The current documentation of 's drain with the whole "if the iterator is dropped..., if the iterator is not dropped" does implicitly suggest that leaking the iterator is a normal interaction, so I guess my personal opinion would be that that documentation should be changed, in line with what I said here Unlike other data types, of course has no validity constraints (beyond the memory-safety relevant ones that can’t be broken by safe API anyways), so of course this option to leave the collection in an invalid state is actually not an option. Whether it is an option for those other data types with validity constraints is a different question (which – as you know – we’re discussing a bit in ). I fully agree with the observation, and as noted above, I also agree that the wording in terms of "Removes the specified range from the vector, returning all removed elements as an iterator" is easier to understand. I now also agree that this describes the intention of what does, and the fact that it can avoid additional allocations by having the iterator access the data structure internals (and patch up the remainder on drop) is basically just an implementation detail. I would not agree that we should ever actually consider to change the implementation by introducing an allocation. I feel like methods are a great example of the strength of Rust to provide zero-overhead abstractions. The abstraction says "remove elements and return an iterator containing them", but the actual implementation saves all the allocation and extra copying steps that you would need for this kind of API in any programming language that isn’t Rust. Of course for a hypothetical method, this kind of optimization is not possible, because there isn’t actually any memory that can be preserved either. E.g. its method just does , while ing a , , or preserves the existing allocation and capacity. Arguably doesn’t even need a method, because you could just as well do . But by the same token it doesn’t need a method either (you can do yourself), so a method can make sense for convenience.
Not true. A map can have an allocated, empty root node or no root node at all. It's just a possibly tiny part and that's probably why it receives no attention. Doing the same trick as in is possible, you can in theory avoid all allocations while owning the map internals. But it's excruciatingly difficult. And the biggest optimization is reusing subtrees with ranges of keys, which doesn't need any trickery. BTreeMap's could preserve the root, just like describes and does. That's true for all drain methods without arguments. My proposed (rotting away in ) takes a range argument, just like Vec's.
Ah, okay I see. Oh, was this “proposed ” one that accepts a range? <hrWell, but e.g. explicitly documents that the underlying allocated memory is kept, which is not* what happens on .
Yes, takes a range (it's buried as ). Another good point, I can't remember anyone bringing that up all the way since my first attempt at a rangeless drain, .

Discussion:
self.rebuild_tail(start); } <del> /// Returns an iterator which retrieves elements in heap order. /// The retrieved elements are removed from the original heap. /// The remaining elements will be removed on drop in heap order. </del> <ins> /// Clears the binary heap, returning an iterator over the removed elements /// in heap order. If the iterator is dropped before being fully consumed, /// it drops the remaining elements in heap order. /// /// The returned iterator keeps a mutable borrow on the heap to optimize /// its implementation. </ins> /// /// Note: /// * `.drain_sorted()` is *O*(*n* * log(*n*)); much slower than `.drain()`.

self.len() == 0 } <del> /// Clears the binary heap, returning an iterator over the removed elements. </del> <ins> /// Clears the binary heap, returning an iterator over the removed elements /// in arbitrary order. If the iterator is dropped before being fully /// consumed, it drops the remaining elements in arbitrary order. </ins> /// <del> /// The elements are removed in arbitrary order. </del> <ins> /// The returned iterator keeps a mutable borrow on the heap to optimize /// its implementation. </ins> /// /// # Examples ///

unsafe { IterMut::new(ring, tail, head, PhantomData) } } <del> /// Creates a draining iterator that removes the specified range in the /// deque and yields the removed items. </del> <ins> /// Removes the specified range from the deque in bulk, returning all /// removed elements as an iterator. If the iterator is dropped before /// being fully consumed, it drops the remaining removed elements. </ins> /// <del> /// Note 1: The element range is removed even if the iterator is not /// consumed until the end. </del> <ins> /// The returned iterator keeps a mutable borrow on the queue to optimize /// its implementation. </ins> /// <del> /// Note 2: It is unspecified how many elements are removed from the deque, /// if the `Drain` value is not dropped, but the borrow it holds expires /// (e.g., due to `mem::forget`). </del> /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the deque. /// <ins> /// # Leaking /// /// If the returned iterator goes out of scope without being dropped (due to /// [`mem::forget`], for example), the deque may have lost and leaked /// elements arbitrarily, including elements outside the range. /// </ins> /// # Examples /// /// ```

/// assert_eq!(drained, [3]); /// assert_eq!(deque, [1, 2]); /// <del> /// // A full range clears all contents </del> <ins> /// // A full range clears all contents, like `clear()` does </ins> /// deque.drain(..); /// assert!(deque.is_empty()); /// ```

self.vec.clear() } <del> /// Creates a draining iterator that removes the specified range in the `String` /// and yields the removed `chars`. </del> <ins> /// Removes the specified range from the string in bulk, returning all /// removed characters as an iterator. </ins> /// <del> /// Note: The element range is removed even if the iterator is not /// consumed until the end. </del> <ins> /// The returned iterator keeps a mutable borrow on the string to optimize /// its implementation. </ins> /// /// # Panics /// /// Panics if the starting point or end point do not lie on a [`char`] /// boundary, or if they're out of bounds. /// <ins> /// # Leaking /// /// If the returned iterator goes out of scope without being dropped (due to /// [`core::mem::forget`], for example), the string may still contain a copy /// of any drained characters, or may have lost characters arbitrarily, /// including characters outside the range. /// </ins> /// # Examples /// /// Basic usage:

/// assert_eq!(t, "α is alpha, "); /// assert_eq!(s, "β is beta"); /// <del> /// // A full range clears the string </del> <ins> /// // A full range clears the string, like `clear()` does </ins> /// s.drain(..); /// assert_eq!(s, ""); /// ```

self.len += count; } <del> /// Creates a draining iterator that removes the specified range in the vector /// and yields the removed items. </del> <ins> /// Removes the specified range from the vector in bulk, returning all /// removed elements as an iterator. If the iterator is dropped before /// being fully consumed, it drops the remaining removed elements. </ins> /// <del> /// When the iterator **is** dropped, all elements in the range are removed /// from the vector, even if the iterator was not fully consumed. If the /// iterator **is not** dropped (with [`mem::forget`] for example), it is /// unspecified how many elements are removed. </del> <ins> /// The returned iterator keeps a mutable borrow on the vector to optimize /// its implementation. </ins> /// /// # Panics /// /// Panics if the starting point is greater than the end point or if /// the end point is greater than the length of the vector. /// <ins> /// # Leaking /// /// If the returned iterator goes out of scope without being dropped (due to /// [`mem::forget`], for example), the vector may have lost and leaked /// elements arbitrarily, including elements outside the range. /// </ins> /// # Examples /// /// ```

/// assert_eq!(v, &[1]); /// assert_eq!(u, &[2, 3]); /// <del> /// // A full range clears the vector </del> <ins> /// // A full range clears the vector, like `clear()` does </ins> /// v.drain(..); /// assert_eq!(v, &[]); /// ```

/// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. /// <ins> /// If the returned iterator is dropped before being fully consumed, it /// drops the remaining key-value pairs. The returned iterator keeps a /// mutable borrow on the vector to optimize its implementation. /// </ins> /// # Examples /// /// ```

self.base.is_empty() } <del> /// Clears the set, returning all elements in an iterator. </del> <ins> /// Clears the set, returning all elements as an iterator. Keeps the /// allocated memory for reuse. /// /// If the returned iterator is dropped before being fully consumed, it /// drops the remaining elements. The returned iterator keeps a mutable /// borrow on the vector to optimize its implementation. </ins> /// /// # Examples ///