Skip to content

Distribution::sample_iter could use owned values instead of references to be more general #602

@huonw

Description

@huonw

Distribution::sample_iter and the DistIter type currently have signature:

fn sample_iter<'a, R>(&'a self, rng: &'a mut R) -> DistIter<'a, Self, R, T> { ... }

struct DistIter<'a, D: 'a, R: 'a, T> { ... }

The lifetimes and borrowing mean that it is impossible to construct a distribution or RNG inside a function and return the sample_iter, e.g. if one is trying to abstract some iterator pipeline

fn ten_dice_rolls_other_than_five<'a, R: Rng>(rng: &'a mut R) -> impl Iterator<i32> + 'a {
    Uniform::new_inclusive(1, 6)
        .sample_iter(rng)
        .filter(|x| *x != 5)
        .take(10)
}

However, these lifetimes aren't entirely necessary, because of the impls of Distribution for &D and RngCore for &mut R:

impl<'a, T, D: Distribution<T>> Distribution<T> for &'a D
impl<'a, R> RngCore for &'a mut R where R: RngCore + ?Sized

(Side note: the Distribution impl could use D: ?Sized like RngCore, to allow &Distribution<T> trait objects to impl Distribution<T>.)

These impls mean that the signature for sample_iter and definition of DistIter could be simplified to:

fn sample_iter<R>(self, rng: R) -> DistIter<Self, R, T> { ... }

struct DistIter<D, R, T> { ... }

The impls above specifically mean that if someone wants to pass a borrowed rng they still can, and similarly for a borrowed distribution. This also applies to Rng::sample_iter (both parameters should become owned).

See https://play.rust-lang.org/?gist=c050e777ed23fb40e320ba0eb340d031&version=stable&mode=debug&edition=2015 for a playground demonstrating the problem with the old API and how the new API fixes it without breaking (much) code.

It also shows that a by_ref function similar to Iterator::by_ref (and Read and Write) may be useful with this sort of API, to use as a postfix &/&mut:

trait RngCore {
    ...
    fn by_ref(&mut self) -> &mut Self { self }
}
trait Distribution<T> {
    ... 
    fn by_ref(&self) -> &Self { self }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions