Currently, there is no way to partially initialize a struct that may have fields added to it later on without a breaking change.
For example, you have struct Foo
:
pub struct Foo {
a: usize,
b: usize,
}
and you want users to be able to initialize like this:
let foo = Foo {
a: 0,
b: 1,
};
However, you also want to be able to add new fields to Foo
later on like, for example, in wgpu-rs, a Rust implementation of the WebGPU standard.
We want to be able to have users do things like this:
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
push_constant_ranges: &[wgpu::PushConstantRange {
stages: wgpu::ShaderStage::FRAGMENT,
range: 0..4,
}],
..wgpu::PipelineLayoutDescriptor::new(&[&bind_group_layout])
})
but, if we add another field to wgpu::PipelineLayoutDescriptor
, it's a breaking change to the api no matter what we do because if we want to support this partial initialization syntax, all the fields of the struct must be public, so the user can just initialize it like a normal structure.
What we wish we could do
Ideally, we could either use the #[non_exhaustive]
attribute, which seems like it should work in this case, but it turns out that no initialization, partial or full, is allowed for a struct with that attribute.
We could also try having private fields so the user is forced to use partial init syntax, but it turns out that the desugaring of partial init syntax actually doesn't allow that.
Solution
There have been a few attempts to change this behavior, but so far, the attempts have created breaking changes. We believe there's a way to implement this without breaking changes by following the following rules: (courtesy of @kvark)
-
is it a private field? if not, proceed as usual
-
is the source container borrowed (as opposed to moved)? if not, move the value in
-
is the source container copyable? if yes, copy the value in, otherwise:
-
issue a compile error, specifying that there is a field Xxx in a borrowed struct that can't be initialized because the struct is not
Copy
.
This seems like a pretty small change to me, so I don't think it'd need an RFC, but I can write one if that's the right way forward. I'm also happy to implement this.
For some urgency, we'd like to get the ability to do partial init syntax while still allowing for the addition of more struct fields without needing to do a breaking change before the WebGPU MVP is standardized. So, as soon as possible.
Alternatives
The alternatives to partial init are
- Builders
- Mutation
Builders are probably better than mutation for this case, but they also add a lot of unnecessary line noise and also diverge significantly from the javascript syntax that the WebGPU standard uses.