Open LikeLakers2 opened 2 weeks ago
The rand
lib used to have similar functionality which was deprecated (largely because of other changes which would have required significant revision to the macro and a lack of usage.) Interestingly, rand_derive
now has 7 reverse-deps.
We could, then, add derive support. It would not be part of the rand
crate but a separate crate.
It should be obvious that all such fields would be sampled independently, thus e.g. samples of Vec3
above would fill a cube not a sphere in 3D space. I wouldn't be surprised if some users fail to realise this however.
On the above snippets:
#[derive(UniformRand)]
— yeah, not ideal having to use a fake name. I'd be tempted to provide an impl-tools::autoimpl
implementation instead just because that supports paths. (I wrote impl-tools
because standard custom derives don't provide enough flexibility, though I don't think we'd have any use for its other features like ignore
field / using
field / enum
support here.) Maybe just #[derive(rand_distr_Uniform)]
is good enough.struct Vec3UniformSampler
— a "derive" macro should be hygenic and not dump extra items into the current scope. Unfortunately I don't think this is solvable, so I guess documenting this is about all we can do.Uniform
/ Standard
. We may remove support for Option
in the next release, and we won't try to support a vast number of generic types. This does limit the usefulness of a derive macro, though not remove it's uses completely.I meant to post this yesterday: Shortly after making this feature request, I decided to start work on https://github.com/LikeLakers2/michis_rand_distr_derive, which is a proc-macro crate for deriving Standard
and Uniform
distributions for a struct.
However, its primary use is as derive-macro practice for myself - and in any case, it's not finished. Still, I wonder if it may be useful to some folks?
@dhardy Thanks for the comments. RE the snippets:
#[derive(UniformRand)]
— yeah, not ideal having to use a fake name.
Just to make sure I understand: When you say "fake name", you're referring to UniformRand
expanding into items that aren't called UniformRand
?
struct Vec3UniformSampler
— a "derive" macro should be hygenic and not dump extra items into the current scope. Unfortunately I don't think this is solvable, so I guess documenting this is about all we can do.
I do admit that a derive macro doing more than implementing a trait is odd. However, I'm not sure an attribute macro:
#[generate_uniform_support]
struct Vec3(f32, f32, f32);
or a function-like macro:
generate_uniform_support! {
struct Vec3(f32, f32, f32);
}
would be any better, since several items (impl SampleUniform for MyType
, struct MyTypeUniformSampler
, and impl UniformSampler for MyTypeUniformSampler
) need to exist for Uniform
support to be possible.
I can see the general use case for creating test instances of structs. I also don't think that people would care about the details of the resulting distribution (cube vs sphere), they just want something "random"
For this usecase a GetRandomInstance
trait would probably ideal and it would also not interfere with what we already have. Option
and Result
could also implement this, because users would not care to much about the exact distributions of this trait.
Probably this would be functionality for it's own crate outside of the scope of rand. But I also see the appeal of rand being the one stop thing for everything random.
would be any better
They're not. I guess what we could do is something like this:
[#derive_distr(Uniform, sampler=Vec3Uniform)]`
struct Vec3(f32, f32, f32);
in order to let users supply a name... but that is overly complicated (also less obvious what it does just reading it).
GetRandomInstance
trait
You are referring to something like the old Rand
trait? The limitation is that this only works for what we're probably now(#1297) calling StandardUniform
, not also parametrised samplers like Uniform
.
You are referring to something like the old
Rand
trait? The limitation is that this only works for what we're probably now(#1297) callingStandardUniform
, not also parametrised samplers likeUniform
.
Yes. I think this limitation is fine if someone just wants something random. If you need more control you implement it yourself.
Background
What is your motivation?
rand
offers theStandard
andUniform
distributions, for making random samples of a primitive or struct. However, to implement them for a new type, the impls (impl Distribution<T> for Standard
forStandard
;impl SampleUniform for T
andimpl UniformSampler for TUniformSampler
forUniform
) must currently be hand-written.What type of application is this?
No specific type of application, though I write this after having to manually implement
Uniform
distribution support for theglam
crate.Feature request
I propose that derives be added for the
Standard
andUniform
distributions. When used on a struct where all fields already implement support for that type of distribution, it will generate the needed code to useStandard
/Uniform
distributions with that struct.A derive for the
Standard
distribution would probably look like this (click the arrow to expand):Standard distribution derive
```rust #[derive(StandardRand)] struct Vec3 { x: f32, y: f32, z: f32, } ``` This derive would generate code similar to the following: ```rust impl DistributionA derive for the
Uniform
distribution would be much the same, albeit with the addition of a struct being generated for theUniformSampler
impl:Uniform distribution derive
```rust #[derive(UniformRand)] struct Vec3 { x: f32, y: f32, z: f32, } ``` generates the following code: ```rust impl SampleUniform for Vec3 { type Sampler = Vec3UniformSampler; } struct Vec3UniformSampler { x_gen: UniformIf I've missed any details, or if there's any questions you have for me regarding this suggestion, please don't hesitate to let me know.