-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possible rustc language features for less magic? #71
Comments
If an |
#[derive(Default)]
struct UwuBuilder {
/// required
#[option_must_be_some_compile_error(message = "owo is required")]
owo: Option<usize>,
/// optional
uwu: Option<usize>,
}
impl UwuBuilder {
fn owo(self, owo) -> Self {
self.owo = Some(owo);
self
}
fn uwu(self, uwu) -> Self {
self.uwu = Some(uwu);
self
}
fn build(self) {}
}
UwuBuilder::default().owo(1).uwu(2).build(); // Compiles
UwuBuilder::default().uwu(2).build(); // Does not compile, because `UwuBuilder::owo` is `None` That would be idea. Makes more sense? But as I said, no idea if it's feasible, especially in terms of type inference. Also adjusted the initial description, as "panic" is misleading, "compiler error" was what I meant. Generally I feel like there's a language feature hiding to help make this whole thing less magic, which would be good, right? |
Why not this? #[derive(Default)]
struct UwuBuilder {
/// required
owo: usize,
/// optional
uwu: Option<usize>,
} |
Then you can't have a builder, can you? Because you would need to instantiate |
Oh. I see your point now - I've somehow missed that you were defining an |
Yeah, I know how your crate is working. The issue was meant to talk about possible language features to not require the hacks that your crate is doing to enable the behavior it's providing β because generating impls on different combinations of tuples ("tuple shadowing" in the initial post) and having an enum without variants so you can't call the build function ("sealed enum" in the initial post) are hacks. Creative hacks, but hacks. |
Sorry if that sounded a bit rude. And if you feel like this is out of scope for your crate specifically, feel free to close. |
Well, if we are talking about language features, how about something like this? struct UwuBuilder<const D: Definition<Self>> {
/// required
owo: usize,
/// optional
#[omittable]
uwu: usize,
}
impl<const D: Definition<UwuBuilder>> UwuBuilder<D> {
fn build(self) -> Uwu {
Uwu {
owo: self.owo,
#[if(D.has("uwu"))]
uwu: self.uwu,
#[if(!D.has("uwu"))]
uwu: 42,
}
}
} And use it like this: assert_eq(
UwuBuilder {
owo: 1,
}.build(),
Uwu {
owo: 1,
uwu: 42,
},
);
assert_eq(
UwuBuilder {
owo: 2,
uwu: 3,
}.build(),
Uwu {
owo: 2,
uwu: 3,
},
); |
Interesting approach! But isn't the tricky part of the generated builder struct that you need to have all fields be struct UwuBuilder<const D: Definition<Self>> {
/// required
owo: usize, wouldn't work, right? |
"Starting empty" is not really a core requirement of the builder pattern. One could imaging a builder that works like this: assert_eq!(
Uwu.builder(2).uwu(3).build(),
Uwu { owo: 2, uwu: 3 },
); Or even: assert_eq!(
UwuBuilder { owo: 2 }.uwu(3).build(),
Uwu { owo: 2, uwu: 3 },
); |
Was just thinking which kind of language features could help with a cleaner approach compared "impl on tuple shadowing" and "sealed enums" β which is a creative way to solve it for sure π. Are you already aware of RFCs that touch on those? Something that came to mind, but no idea if it's feasable: "
Option
must beSome
"-attribute that makes the compiler error if option isNone
The text was updated successfully, but these errors were encountered: