# Try\_reserve returning non-growable Vec view

**URL:** <https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491>\
**Category:** language design\
**Created:** [April 14, 2021, 10:33pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491 "2021-04-14T22:33:49Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [April 14, 2021, 10:33pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/1 "2021-04-14T22:33:49Z")

</div>

For fallible allocations there's been consideration for 3 alternatives:

- `try_reserve() -> Result<()>` followed by YOLO `push()`, or
- `try_push()` on the `Vec` itself,
- or `FallibleVec` twin that has all methods as `try_*`

How about mixing it up, and making `try_reserve` return a non-growable equivalent of `FallibleVec`?

```rust
let reserved_space = vec.try_reserve()?;

reserved_space.try_push(x)?;
// or
// this may panic if it runs out of reserved space, 
// but never reallocates, never OOMs!
reserved_space.push(x); 

```

The idea is that the object returned by `try_reserve` would be a safe wrapper around `MaybeUninit<[T; reserved_size]>`.

I expect that even when OOM handling is not a concern, this would generate slightly more optimized code thanks to more explicitly guaranteed allocated space and no need for handling realloc.

```rust
let mut v = Vec::with_capacity(x);
for item in something_of_len(x) {
   v.push(item);
}

```

That `push()` today adds extra code for `if !has_capacity { realloc() }`. It seems that LLVM is unable to optimize it out.

OTOH:

```rust
let v = Vec::new();
let tmp = v.try_reserve(x);
for item in something_of_len(x) {
   tmp.push(item);
}

```

When `push` can guarantee fixed-size capacity without reallocations, it optimizes beautifully:

> **[Compiler Explorer - Rust (rustc 1.51.0)](https://rust.godbolt.org/z/E74rW56f4)**
>
> // Type your code here, or load an example.
> use std::mem::MaybeUninit;
> 
> \#\[inline(never)\]
> pub fn test1() -\> Vec {
> let mut v = Vec::with\_capacity(100);
> for n in 0..100 {
> v.push(n)
> }
> v
> }
> 
> \#\[inline(never)\]
> pub fn test2() -\>...

It's not relevant for the Linux kernel, because [the plan is that Linux won't use `alloc` crate at all](https://github.com/Rust-for-Linux/linux/issues/2).

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 14, 2021, 11:13pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/2 "2021-04-14T23:13:55Z")

</div>

I like the idea of using a different type here, and allowing for more optimization. However, if it still panics when it runs out of reserved space, that would cause problems for environments that shouldn't panic, such as the Linux kernel.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 15, 2021, 12:43am UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/3 "2021-04-15T00:43:35Z")

</div>

Does the kernel need to avoid _all_ panics, or just those related to allocation failure and unsupported features like floating point?

Or in other words, is a kernel panic okay e.g. when indexing out of bounds? Panicking push is basically the same thing- assuming it's not caused by input from userspace/network/device/etc, and thus not an expected failure mode, there's not much to do in response. AFAIK there's no EKERNELBUG the way there is ENOMEM.

Or in _other_ words, clearly the kernel does have panics and `BUG` and such- when _are_ those appropriate to use?

Or more generally, Rust relies on panics in a lot of places where C just has undefined behavior and the kernel doesn't want to go in the first place. Is turning those into kernel panics an acceptable way to get a sound language, or is a new language not worth it unless it can catch all of them at compile time?

---

<div class="post-metadata">

**Author:** ![Nokel81](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nokel81/32/3966_2.png) [@Nokel81](https://internals.rust-lang.org/u/Nokel81)\
**Post date:** [April 15, 2021, 12:51am UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/4 "2021-04-15T00:51:24Z")

</div>

From what I read of Linus' response to the RFC for allowing rust into the Linux kernel. He is basically against allocation panics. I think he is fine for out of bounds panics since you can avoid them.

But that is just my understanding of it.

---

<div class="post-metadata">

**Author:** ![josh](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/josh/32/5934_2.png) [@josh](https://internals.rust-lang.org/u/josh)\
**Post date:** [April 15, 2021, 1:51am UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/5 "2021-04-15T01:51:04Z")

</div>

> [@rpjohnst](#):
>
> Or in other words, is a kernel panic okay e.g. when indexing out of bounds?

In kernel terms, that should probably be an "oops", not a panic. A panic kills the whole kernel; an oops just kills the process that's currently running in the kernel while leaving the rest of the kernel mostly functional (as long as that thread wasn't holding any locks or similar).

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 15, 2021, 2:06am UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/6 "2021-04-15T02:06:30Z")

</div>

Ah, interesting distinction! Do you think Rust panics generally should be treated as "oops"es or would you still want any to be kernel panics? (Or maybe this is already being discussed on the mailing list somewhere?)

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [April 15, 2021, 5:59am UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/7 "2021-04-15T05:59:04Z")

</div>

Sounds great for when you want to push multiple items and you know how many in advance. But this should exist in addition to `Vec::try_push`, rather than being a substitute for it. It's important that fallible allocations be ergonomic. If you only have one item to push, or if you want to push in a loop but you don't know the count in advance, `try_reserve(1)?.push(item)` is needlessly verbose.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [April 15, 2021, 12:26pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/8 "2021-04-15T12:26:42Z")

</div>

Linux [is not planning to use the `alloc` crate](https://github.com/Rust-for-Linux/linux/issues/2) and will instead implement kernel-specific containers from scratch.

I think providing a solid no-panic guarantee (as requested by Linus) is a separate problem, e.g. there's no plan to remove `Index` support from `Vec` or slices, so the no-panic enforcement must be done in some other way. It can't be done by merely not implementing maybe-panicking interfaces.

Also keep in mind that Rust currently aborts on OOM, and custom OOM handlers are not allowed to unwind, so OOM handling in Rust is very destructive. Replacing risk of OOM-abort with a risk of a mere panic is already a big improvement.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [April 15, 2021, 4:06pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/9 "2021-04-15T16:06:51Z")

</div>

> [@kornel](#):
>
> Linux [is not planning to use the `alloc` crate](https://github.com/Rust-for-Linux/linux/issues/2) and will instead implement kernel-specific containers from scratch.

And for now that's clearly the right way to go. Linux can experiment with API design, in a codebase that has zero API backwards compatibility requirements, while preserving the ability to compile old Linux versions with new compilers.

But I'd like to see `alloc` evolve to the point where Linux could hypothetically move back to it some day. Where, if the functionality had existed today, it would have been a no-brainer for Linux to use it instead of implementing their own.

(In this scenario, Linux might still want some custom container implementations optimized for specific needs, but those implementations would be written on top of `alloc` and would imitate the API design of standard containers.)

Even if Linux never actually moves back to `alloc`, Linux's requirements are close enough to those of other kernels, and really any project that wants to handle memory allocation failure [(say, Hyper as used by curl)](https://github.com/hyperium/hyper/issues/2265#issuecomment-694043499), that it makes an excellent reference point.

In particular, those requirements may include not just the ability to handle allocation failure, but the ability to pass some kind of argument to the allocator, corresponding to the `flags` argument to `kmalloc`.

I'll be very interested to see how this all plays out in practice.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [July 14, 2021, 4:07pm UTC](https://internals.rust-lang.org/t/try-reserve-returning-non-growable-vec-view/14491/10 "2021-07-14T16:07:46Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
