Way to make a configuration struct stable across versions?
malucard:
Also, obviously, an alternative way to implement this would be to use a builder. The problem is that that's way too much work. A struct would be much more ergonomic, and there should be no need to create a function for each field.
I think a builder here is more ergonomic for the user. A builder could easily look like
let triangle_pipeline = RasterPipelineOptions::default()
.vertex_shader(triangle_shader_module.get("vertex"))
.fragment_shader(triangle_shader_module.get("fragment"))
.create_with(device)?;
which has less nesting, avoids writing "raster pipeline" twice, and avoids the Some(...)'s which are just expressing the fact that you have chosen to include this option rather than omit it (there is almost no circumstance where you would write RasterPipelineOptions { vertex_shader: None, ..Default::default() }; the Some is not communicating valuable information, it is just visual clutter required by the direct field assignment).
It's true that making the option struct function nicely as a builder would take more work, but it is also something that could be accomplished by a derive macro (at least if you're okay with .vertex_shader(Some(...)) instead of .vertex_shader(...) or using attributes to specify when optional values should be implicit) or even a simple declarative macro. If you're adding an attribute to support this anyway, it doesn't seem like there's that much gained over just adding a macro for making builder structs.
I'll admit one disadvantage of the macro-generated builder approach is that it plays somewhat less nicely with LSPs, but I think it's probably better overall in most cases.
Discussion in the ATmosphere