lundi 19 octobre 2020

To implement extremely complex generic accessor trait over T, &T, &mut T or to define 3 differents traits?

Often, in Rust code, we find functions with name similar to as_ptr, as_mut_ptr that does the same but differs in the mutability of both there return type and the receiver type.

I am implementing a kind of trait that, for the purpose of this question, can be reduced to an accessor trait. As this accessor may be used to get a reference, a mutable reference or a value, and as there are some implementors that can provides the 3 access forms, one option I have is to provide 3 traits.

 trait Alternative {
     fn alternative<I>(self) -> AlternativeOf<I,Self>;
   }
   trait AlternativeRef {
     fn alternative_ref<I>(&self) -> &AlternativeOf<I,Self>;
   }
   trait AlternativeMut {
     fn alternative_mut<I>(&mut self) -> &mut AlternativeOf<I,Self>;
   }

   impl Alternative for Implementor {/*...*/}
   impl Alternative Implementor {/*...*/}
   impl Alternative for Implementor {/*...*/}

I think this is the usual design pattern in Rust.

My problem with this pattern is the amplitude of the vocabulary of my crate. My opinion is that the vocabulary of my crate is too large. One of the reason is that there are also mutation/constness over a second parameter so that there are functions whose name has the form mut_get_mut, ref_get_mut, mut_get_ref, ...

In C++, where functions can be overloaded, it is common to overload for &T and &mut T. I have just figured out that with Rust we can go even further as, thanks to traits, we can overload for T, &T and &mut T:

 trait Alternative {
     fn alternative<I>(self) -> AlternativeOf<I,Self>;
   }

   impl Alternative for Implementor {/*...*/}
   impl<'a> Alternative &'a Implementor {/*...*/}
   impl<'a> Alternative for &'a mut Implementor {/*...*/}

I have made few experiments, it seems to works. Hopefully, I will be able to divide the vocabulary of my crate by 3, and to turn confusing names as mut_alternative_ref into less confusing ones. But I am surprised not to see this pattern in other Rust code or in the standard library.

Why this last design pattern not used in Rust code? Should I continue and change my code to decrease the amplitude of my crate vocabulary or should I stick with the usual pattern involving different method name for the different receiver types?

Aucun commentaire:

Enregistrer un commentaire