Description
In general the new API in 0.11 works nicely, but one pain point I had was mapping Option<Foo>
values (which I either calculate on the fly or have stored in a data structure) to optional builder method calls. For example, I'll have an expression which results in an Option<&str>
for the origin of a Snippet
, where None
means that it won't have one. This worked great in the 0.10.x API because I could just assign my value to the relevant field of the annotate-snippets data structure, since it was also an Option
. In the new 0.11.1 API I now either need to call Snippet.origin(...)
(if my value is Some
) or not call it (if my value is None
), which really breaks the nice ergonomics of chaining all of the needed builder method calls.
For example:
let mut snippet = Snippet::source(buffer)
.line_start(1)
.fold(true)
.annotations(...)
;
if let Some(origin) = my_optional_origin_expression {
snippet = snippet.origin(origin);
}
Consider the potential improvement if there was a builder method that took an Option
:
Snippet::source(buffer)
.line_start(1)
.fold(true)
.annotations(...)
.maybe_origin(my_optional_origin_expression)
Now the entire thing is a single expression -- which could e.g. be passed straight to another builder function -- instead of requiring a temporary mutable variable and conditional logic.
It's also interesting to consider the inconsistency with the Snippet::fold
method, which doesn't have this problem. I can have a bool
value (or expression) that controls whether folding should be enabled or disabled and pass it straight to fold
rather than needing logic to either call fold
(in the true
case) or not call it (in the false
) case. If fold
were consistent with the other builder methods as they currently are, then it would take no parameters and always turn folding on when called. To be clear, though, I'm not advocating that you should change fold
to be that way; I'm actually advocating the opposite, that you change the other builder methods (or add additional ones) for consistency with how fold
currently is, i.e. allow them to be used to explicitly specify the default value.
My workaround for this was to make little extension traits and add my own maybe_*
versions of relevant builder methods (so far just Snippet::maybe_origin
and Annotation::maybe_label
). While that's an entirely technically valid solution, I feel like there's a pretty good chance that such builder methods would end up being used often enough as to warrant their inclusion in the crate's API.