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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions