# Is there a reason why Vec::len is not a const fn?

**URL:** <https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920>\
**Category:** language design\
**Created:** [January 27, 2021, 3:07pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920 "2021-01-27T15:07:40Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![sharazam](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sharazam/32/2667_2.png) [@sharazam](https://internals.rust-lang.org/u/sharazam)\
**Post date:** [January 27, 2021, 3:07pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/1 "2021-01-27T15:07:40Z")

</div>

[https://doc.rust-lang.org/src/alloc/vec.rs.html#1365-1367](https://doc.rust-lang.org/src/alloc/vec.rs.html#1365-1367)

Technically `Vec::len()` could be a `const fn`, is there any reason why that's not the case or was it just overlooked? Thanks.

---

<div class="post-metadata">

**Author:** ![tesuji](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tesuji/32/12790_2.png) [@tesuji](https://internals.rust-lang.org/u/tesuji)\
**Post date:** [January 27, 2021, 3:26pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/2 "2021-01-27T15:26:50Z")

</div>

The reason is that Vec cannot be constant except for empty vec.

---

<div class="post-metadata">

**Author:** ![bascule](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bascule/32/3057_2.png) [@bascule](https://internals.rust-lang.org/u/bascule)\
**Post date:** [January 27, 2021, 3:41pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/3 "2021-01-27T15:41:04Z")

</div>

See the const-eval issue for [heap allocations in constants](https://github.com/rust-lang/const-eval/issues/20)

---

<div class="post-metadata">

**Author:** ![sharazam](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sharazam/32/2667_2.png) [@sharazam](https://internals.rust-lang.org/u/sharazam)\
**Post date:** [January 27, 2021, 3:45pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/4 "2021-01-27T15:45:53Z")

</div>

Yes, but that's not what I need it for. but conversions into other custom types could be const:

```rust
#[repr(C)]
pub struct BlahVec {
    ptr: *const Blah,
    len: usize,
    cap: usize,
    destructor: BlahDestructor,
}

#[repr(C, u8)]
pub enum BlahDestructor {
    DefaultRust,
    NoDestructor,
    External(extern "C" fn(*mut BlahVecDestructor)),
}

impl BlahVec {

    #[inline(always)]
    pub const fn new() -> Self {
        Self::from_vec(Vec::<Blah>::new())
    }

    // I want this conversion fn to be const, that's why
    #[inline(always)]
    pub const fn from_vec(v: Vec<Blah>) -> BlahVec {
        use std::mem::ManuallyDrop;

        // note: &[T]::as_ref() is a const fn, Vec<T>::as_ptr() is not?

        let ptr = (&v[..]).as_ptr();
        let len = (&v[..]).len();
        let cap = (&v[..]).capacity();

        let _ = ManuallyDrop::new(v);

        BlahVec {
            ptr,
            len,
            cap,
            destructor: BlahVecDestructor::DefaultRust,
        }
    }
}

impl Drop for BlahVec {
    fn drop(&mut self) {
        match self.destructor {
            BlahVecDestructor::DefaultRust => { let _ = unsafe { Vec::from_raw_parts(self.ptr as *mut Blah, self.len, self.cap) }; },
            BlahVecDestructor::NoDestructor => { },
            BlahVecDestructor::External(f) => { f(self); }
        }
    }
}

```

I'm then creating the Vec from a `&'static [u8]`, so the len() is non-zero and also known at compile time. Yes I know this is all unsafe, but I'm not using dynamic allocation.

---

<div class="post-metadata">

**Author:** ![tesuji](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tesuji/32/12790_2.png) [@tesuji](https://internals.rust-lang.org/u/tesuji)\
**Post date:** [January 27, 2021, 3:54pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/5 "2021-01-27T15:54:27Z")

</div>

So you might want to use ArrayVec or the likes, which uses stack as storage.

---

<div class="post-metadata">

**Author:** ![sharazam](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sharazam/32/2667_2.png) [@sharazam](https://internals.rust-lang.org/u/sharazam)\
**Post date:** [January 27, 2021, 4:35pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/6 "2021-01-27T16:35:34Z")

</div>

Well I've solved it now by making two separate functions, one for `new()` and one for `new_nonconst()`:

```rust
impl BlahVec {
    #[inline(always)]
    pub fn new() -> BlahVec {
        use std::mem::ManuallyDrop;
        let v = Vec::new();
        let md = ManuallyDrop::new(v);

        BlahVec {
            ptr: md.as_ptr(),
            len: 0,
            cap: 0,
            destructor: $destructor_name::DefaultRust,
        }
    }
}

```

I can't use `ArrayVec` or similar because I also need to handle pointers to memory not managed by Rust (i.e. allocated by a C++ `std::vector`) as well as pointers into static memory (i.e. `&'static [T]`) as well as regular Rust `Vec<T>` in one type with as little conversion code as possible.

I can set the `ptr` and `cap` to 0, but I can't get the `.get_ptr()` in a const fn. Right now I've made everything non-const and hope that the optimizer catches it, it works but it's not a great solution.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [January 27, 2021, 11:20pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/7 "2021-01-27T23:20:16Z")

</div>

> [@sharazam](#):
>
> made everything non-const and hope that the optimizer catches it

Unless you're putting the result into a `const` context (i.e. you have `const SOMETHING` or `static SOMETHING` at the use site), `const` has no impact on the pre-evaluation of the value. If it's inlined to a precomputed value, that's on the optimizer to do, even if you mark it `const`.

(IOW, `const` does not mean "constant evaluate this if all inputs are constant", it means "this is constant evaluable, only such that it can be put in a constant compiletime value".)

There are vague murmurings of a future `const {}` block which would force constant evaluation of its contents (roughly by making it a const context) even in non-const contexts.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [January 27, 2021, 11:45pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/8 "2021-01-27T23:45:49Z")

</div>

> [@CAD97](#):
>
> There are vague murmurings of a future `const {}` block

They're a little further along than that 😛

[https://rust-lang.github.io/rfcs/2920-inline-const.html](https://rust-lang.github.io/rfcs/2920-inline-const.html)

---

<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:** [April 27, 2021, 11:46pm UTC](https://internals.rust-lang.org/t/is-there-a-reason-why-vec-len-is-not-a-const-fn/13920/9 "2021-04-27T23:46:06Z")

</div>

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