2 ms·
If I were changing the signature of `do_something` in Rust and wanted to avoid breaking callers when changing the function from accepting `T` to `Option<T>` , I
by saghm 3y ago
If I were changing the signature of `do_something` in Rust and wanted to avoid breaking callers when changing the function from accepting `T` to `Option<T>` , I'd do the following:
fn do_something(value: impl Into<Option<T>>) {
let value = value.into();
// remaining function body using `value` as an `Option<T>`
}
Existing calls to `do_something` will continue working because `Option<T>` implements `From<T>` (and `Into` implementations are generated in the opposite direction whenever `From` is implemented). Passing in `None` will also work because every type `T` implements `From<T>`, and therefore `Into<T>` as well.
I'd even argue that in a lot of cases, this is worth doing even when creating new library functions (where there are no existing callers to worry about). In my experience, it's generally better to keep the API clean from a caller's perspective by taking on extra boilerplate internally in the implementation rather than shift the burden to the callers of the API in order to keep the library's implementation clean.
- skavi 3y agoOften better to do the conversion then immediately call a non generic inner function. This prevents the rest of the logic from getting monomorphized. It’s a pattern you’ll notice in std.
- skitter 3y agoThis is a breaking change too, as it can break type inference: https://play.rust-lang.org/?edition=2021&gist=8d528bcec2b92b73780d3335d936dfcb https://play.rust-lang.org/?edition=2021&gist=8d528bcec2b92b...
- obi1kenobi 3y agoInterestingly, even though it's a breaking change, breaking inference is explicitly defined to not be a semver-major change in Rust: https://predr.ag/blog/some-rust-breaking-changes-do-not-require-major-version/ https://predr.ag/blog/some-rust-breaking-changes-do-not-requ...