Skip to content

[Reasoning] A valid const-generic impl Default for arrays, and eventually working to a TryFromIter implementation... #71514

@ZaneHannanAU

Description

@ZaneHannanAU

This is mostly an ideas test for potentially introducing a generic impl for Default over an array of any size, rather than just up to 32.

My current implementation does not, unfortunately, implement default for arrays at zero cost; but could be useful for further checks:

use ::core::mem::MaybeUninit;
#[derive(Copy, Clone, Debug)]
struct ImplDefaultConstArray<T: Default, const N: usize> {
  arr: MaybeUninit<[T; N]>,
  idx: usize,
}
unsafe impl<T: Default, const N: usize> Drop for ImplDefaultConstArray<T, { N }> {
  fn drop(&mut self) {
    let _assigned = self.arr[..self.idx];
    // let it drop normally
  }
}
impl<T: Default, const N: usize> Default for [T; N] {
  fn default() -> Self {
    let uninit = ImplDefaultConstArray {
      arr: MaybeUninit::uninit(),
      idx: 0,
    };
    while uninit.idx < N {
      uninit.arr[uninit.idx] = T::default();
      uninit.idx += 1;
    }
    unsafe { uninit.arr.assume_init() }
  }
}

Unfortunately I believe this currently is an erroneous implementation, and has other issues regarding the real cost of it.

This could also be implemented in a less technical way if FromIterator on arrays stabilises, or rather a TryFromIterator implementation detailed below arises (note the try_collect)

use ::core::iter;
impl<T: Default, const N: usize> Default for [T; N]
  fn default() -> Self {
    #[cfg(feature = "impl_take_const")]
    iter::repeat_with(T::default)
      .take(N)
      .try_collect()
      .unwrap()
    #[cfg(not(feature = "impl_take_const"))]
    {
      let mut idx = 0;
      iter::from_fn(|| if idx < N {
        *idx += 1;
        Some(T::default())
      } else {
        None
      })
      .try_collect()
      .unwrap()
    }
  }
}

Or the original code could be a part of a generic implementation of FromIterator, or a potential trait TryFromIterator where type Error is of type TryFromSliceError, or a similarly zero-sized TryFromIteratorError; and a further is added:

impl<T: FromIterator, I> TryFromIterator<Item = I> for T {
  type Error = !;
  fn try_from_iter<Iter: Iterator<Item = I>(iter: Iter) -> Result<Self, Self::Error> {
    Ok(T::from_iter(iter))
  }
}

... I thank you for your time.

p.s: I also should really stop writing these so early... and need to adopt more official language in this circumstance. If someone can write this up as a feature request or PR more officially, that'd be amazing. Thank you.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-const-genericsArea: const generics (parameters and arguments)C-feature-requestCategory: A feature request, i.e: not implemented / a PR.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions