3 ms·
Disclaimer: I have been (re-)learning Rust recently through some toy projects. > Type aliases are transparent (as opposed to abstract) by default, exposing the
by smilekzs 4y ago
Disclaimer: I have been (re-)learning Rust recently through some toy projects.
> Type aliases are transparent (as opposed to abstract) by default, exposing their definitions publicly.
IMHO this hurts a lot because the main alternative, which is the "newtype" pattern (`struct NewType(OldType);`), introduces a lot of friction. Yes, you can `derive`, but it usually takes a lot more to reach "feature parity" with the original type, with only the undesirable parts swapped out. There are libraries to help: `derive_more`, `derivative`, etc. but the qualities vary, you need to find the correct library in the first place, and even then there's no guarantee they play nice with each other...
> conversions: From, TryFrom, Into, TryInto, As, AsRef, AsMut
This makes the 1st point worse TBH. With a myriad of newtypes and typedefs, it soon becomes confusing what can convert to what, through which trait or direct methods.
- moth-fuzz 4y agoI never quite understood why this is the way it is - why is the paradigm impl TryFrom<&T> for U instead of impl Into<Result<U, E>> for &T Why make a separate trait? And why make the blanket impl from-based rather than into-based?
- estebank 4y agoBecause Rust has restrictions on what can be impl'd to containing at least one local type/trait. impl Foo<X> for Y {} ^^^--- ^ one of these two has to belong to your current crate | this part doesn't matter If you tried impl ForeignTrait for ForeignType {} You get a compile error, hence why you can sometimes hear people suggesting using a new-type struct LocalType(ForeignType); impl ForeignTrait for LocalType {} ^^^^^^^^^ this is a local type, so it compiles This restriction is to avoid allowing semver footguns, where changes in a dependency of a dependency can cause your current crate to stop compiling after a seemingly innocuous upstream change. With that context impl Into<Result<U, E>> for &T ^^^^ ^ could be foreign? | foreign (from std::) If you want to provide your users with a way to call .into() on a type you provide, that can be converted to a type they wrote, you need to be able to express the opposite construct, hence `From` impl From<Foreign> for Local ^^^^ ------- ^^^^^ local type, so the impl is allowed | | | foreign, but it doesn't matter foreign (from std::)
- aecay 4y agoThis is a fantastic explanation.