You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It's often useful to wrap a single type into a new one, to be able to add new methods, provide more documentation and possibly type safety.
For example,
pubstructInches(f32);pubstructMeters(f32);
This way if the units are used incorrectly we get a type error. Fortunately there is no space overhead as well. This is very similar to newtype in Haskell.
I'm proposing that we consider being able to derive From and possibly Deref for structs with exactly one field. For the above example, adding #[derive(From, Deref)] above Inches would generate the code:
Disclaimer: I might come across a little rude because english isn't my first language and text isn't very good at conveing emotion in the first place. I'm not writing with animosity towards you - literally the contrary!
I think I'm against this, for the following reason: Syntax and implications.
#[derive(From, Deref)] could confuse many people. Deriving from a very generc trait and making it only legal for rather specific types is odd. I mean what would happen if one attempts to derive these traits for invalid types? "Sorry, your type is not tall enough to ride this ride derive from this trait". Is this really a good idea? Do we really want these specific auto-impls in derive? If I derive from something, I expect to always get a predictable implementation, without errors (excluding other trait requirements, like Eq => PartialEq).
Also I think automatically implementing From for newtypes is not a good idea either. Isn't the point of newtypes to ensure that the data they wrap cant be passed / used somewhere wrong? In other words, binding meaningless data types to specific, statically checked, meaning? Let me reuse your Inches / Meters example:
Let's imagine we have derived From and Deref for both Inches and Meters (or implemented it manually, doesn't really matter). There's nothing stopping me or anyone else from doing stuff like this:
let inches = Inches(123.0);// Somewhere, in the dark corners of your codebase:let meters = Meters::from(*inches);// Rather than:let meters:Meters = inches.into();// Orlet meters = inches.into_meters();
The from-derive variant avoids explicit conversion of the data and would probably introduce bugs to our code.
I believe it's vital to design your API or code generally in such a way, that it cannot be used incorrectly (Scott Meyers, anyone?). From and Deref would make it very easy to use it incorrectly.
Wow, I really don't know how to keep it short. What do you guys think?
Deriving from a very generc trait and making it only legal for rather specific types is odd.
As far as I know, #[derive(Copy)]/Clone/Default/Eq/Ord/etc are only legal on types that contain only other Copy/Clone/Default/Eq/Ord/etc types. So this is nothing new.
The from-derive variant avoids explicit conversion of the data and would probably introduce bugs to our code.
If you have a newtype/wrapper for which the obvious, trivial conversion is invalid, wouldn't you simply not use this feature and write a correct From impl maually? It's not that hard to write a broken From impl today.
automatically implementing From for newtypes
I believe the proposed feature is meant to be opt-in, like existing derive annotations. Most of your post simply doesn't make sense to me; it sounds as if you're talking about an opt-out feature that users would have to know to avoid, rather than an annotation that doesn't do anything until you explicitly add it.
As far as I know, #[derive(Copy)]/Clone/Default/Eq/Ord/etc are only legal on types that contain only other Copy/Clone/Default/Eq/Ord/etc types. So this is nothing new.
True, but what I was talking about was #[derive(From / Deref)] mandating a syntactically specially formed struct (a tuple struct with only one field). What would a programmer, who's unfarmiliar with the derive, think when they came across #[derive(From)]? Would it be clear what it does?
I'd prefer if we would choose more distinct names for the derives, something like #[derive(NewtypeFrom)], but thats not possible I think. How about a custom attribute #[WrapperType], which would implement both Deref and From? That would be totally fine with me.
If you have a newtype/wrapper for which the obvious, trivial conversion is invalid, wouldn't you simply not use this feature and write a correct From impl maually? [...]
Yup, that's what I was trying to show with my snippet, although I was doing it the other way around with Into.
Deref seems quite reasonable, and conveniently there's already a feature that defined "the one field that matters, even if there are extra ZST markers": repr(transparent). (That probably doesn't work if every field is a ZST, but Deref to a ZST feels like an uncommon enough scenario that it doesn't worry me.)
From I'm more torn about. If one can derive From, it feels like one should also be able to derive Into, but that's something we tell people not to implement (if possible). So what I really want for a newtype that has an invariant is InnerFromSelf, but that feels meh.
I remember seeing "we should have explicit support for declaring a newtype" expressed before, but can't seem to fine it...
Deriving From automatically derives Into. If I recall correctly, you get an error if you attempt to derive Into yourself. I don't see the problem there.
@scottmcm I think deriving From is enough; Into will be auto-impled (as @iitalics pointed out). But I do like the idea of InnerFromSelf except maybe it makes more sense as IntoInner instead.
There is a derive_derefcrate with ~68000 downloads for now, and I believe this is a good evidence that #[derive(Deref)] is in demand.
Personally I've been implementing a trivial Deref each time for a newtype, where I use newtype construction for a flow control between interfaces rather than for hiding an internal representation.
The fact that a crate can already reliably do this and also the fact that this isn't an essential part of letting the ecosystem pick a "standard" datatype for something means that this seems like a low priority.
Not that I'm against the idea, but if there's already a crate for it, what does putting it into core gain us?
It would be interesting to survey the uses of derive_deref. In particular, how many of its uses are "real" Derefs as opposed to using Deref as a workaround for the lack of delegation.
It's also not clear to me that "If the type of that field is a reference, the reference will be returned directly." is the correct default behavior for Deref impls in general.
Unfortunately I don't have the time myself to investigate either point.
Yes, I'd worry that #[derive(Deref)] encourages deref polymorphism, which bring subtle problems. At least the variance issues should not be problematic here, right? I suppose Deref/DerefMut have some history with soundness bugs too, but again not with such simple derives probably.
I think rust should first sort out both (a) delegation in general and (b) convenient newtype delegation across many traits. I think (b) could reasonable precede (a) if done properly outside std/core, like maybe the newtype_derive crate, but convenient precise arithmetic, Fn, etc. delegation should be preferred over Deref/DerefMut.
Also, there is a units crate if you want units, so maybe even arithmetic traits should always omit some functionality for newtypes.
Reacted by Jake Goulding and SOFe (Jonathan Chan Kwan Yin)
Yes, I'd worry that #[derive(Deref)] encourages deref polymorphism
In my opinion, I'd worry that the existence of Deref trait itself encourages deref polymorphism, not the existence of #[derive(Deref)] implementation ;)
Kind of, it doesn't stop anyone to implement a little boilerplate impl Deref for MyType, and it doesn't stop using external crates implementing Deref.
I think rust should first sort out both (a) delegation in general and (b) convenient newtype delegation across many traits. I think (b) could reasonable precede (a)...
Yes, agree, if I understand you correctly. I think that seems like newtype could be a main motivation to have a quick #[derive(Deref)] over it. By the way, derive_deref works with limitations that the struct should have only a 1 field (newtype).
I would generally say that a newtype should implement AsRef<Inner> instead of Deref<Target=Inner> so that going to the wrapped type is an explicit step. Otherwise, why are you wrapping the inner value at all.
As to From, that seems reasonable at first, but if there's no guards or checks on the inner value at all, why is the inner field private? If it's a public field you don't really need the From impl.
So it's not that more derives couldn't be in core, but we would probably want stronger motivation for additional core derives. Since derives can be provided via a crate, the bar for adding them to core is relatively high.
As to From, that seems reasonable at first, but if there's no guards or checks on the inner value at all, why is the inner field private? If it's a public field you don't really need the From impl.
Yeps, From is open for discussion while I still see some reason to give some facilities for wrapper types. It might have complex situations, especially the fact that From can be implemented for many "variants".
I would generally say that a newtype should implement AsRef<Inner> instead of Deref<Target=Inner> so that going to the wrapped type is an explicit step. Otherwise, why are you wrapping the inner value at all.
"Deref coercion" is (for me) part for zero-cost abstraction and motivation for a Deref derive. As it can have only one implementation of Deref trait for a struct, it sounds "easier". Especially for singleton tuple. I suppose it must not differ too much than Default derive (in its logic).
The common meaning for "zero cost abstraction" is that it's a "zero runtime overhead abstraction". Writing &x and activating Deref or x.as_ref() and activating AsRef would both satisfy this definition. It's a matter of how explicit we have people be.
If you're bothering to use newtypes to enforce better typing on your expressions, you probably want to have more explicit changes between those types.
Activity
mark-i-m commentedon Jun 11, 2017
Possibly this could be done as a macro, though.
killercup commentedon Jun 12, 2017
Not sure if it's any good, but there is a crate that does just that: https://github.com/JelteF/derive_more
haudan commentedon Jun 13, 2017
Disclaimer: I might come across a little rude because english isn't my first language and text isn't very good at conveing emotion in the first place. I'm not writing with animosity towards you - literally the contrary!
I think I'm against this, for the following reason: Syntax and implications.
#[derive(From, Deref)]could confuse many people. Deriving from a very generc trait and making it only legal for rather specific types is odd. I mean what would happen if one attempts to derive these traits for invalid types? "Sorry, your type is not tall enough toride this ridederive from this trait". Is this really a good idea? Do we really want these specific auto-impls in derive? If I derive from something, I expect to always get a predictable implementation, without errors (excluding other trait requirements, like Eq => PartialEq).Also I think automatically implementing
Fromfor newtypes is not a good idea either. Isn't the point of newtypes to ensure that the data they wrap cant be passed / used somewhere wrong? In other words, binding meaningless data types to specific, statically checked, meaning? Let me reuse your Inches / Meters example:Let's imagine we have derived
FromandDereffor both Inches and Meters (or implemented it manually, doesn't really matter). There's nothing stopping me or anyone else from doing stuff like this:The from-derive variant avoids explicit conversion of the data and would probably introduce bugs to our code.
I believe it's vital to design your API or code generally in such a way, that it cannot be used incorrectly (Scott Meyers, anyone?).
FromandDerefwould make it very easy to use it incorrectly.Wow, I really don't know how to keep it short. What do you guys think?
Ixrec commentedon Jun 13, 2017
As far as I know, #[derive(Copy)]/Clone/Default/Eq/Ord/etc are only legal on types that contain only other Copy/Clone/Default/Eq/Ord/etc types. So this is nothing new.
If you have a newtype/wrapper for which the obvious, trivial conversion is invalid, wouldn't you simply not use this feature and write a correct From impl maually? It's not that hard to write a broken From impl today.
I believe the proposed feature is meant to be opt-in, like existing derive annotations. Most of your post simply doesn't make sense to me; it sounds as if you're talking about an opt-out feature that users would have to know to avoid, rather than an annotation that doesn't do anything until you explicitly add it.
haudan commentedon Jun 14, 2017
True, but what I was talking about was #[derive(From / Deref)] mandating a syntactically specially formed struct (a tuple struct with only one field). What would a programmer, who's unfarmiliar with the derive, think when they came across
#[derive(From)]? Would it be clear what it does?I'd prefer if we would choose more distinct names for the derives, something like
#[derive(NewtypeFrom)], but thats not possible I think. How about a custom attribute#[WrapperType], which would implement both Deref and From? That would be totally fine with me.Yup, that's what I was trying to show with my snippet, although I was doing it the other way around with
Into.Comments?
scottmcm commentedon Jun 29, 2017
Derefseems quite reasonable, and conveniently there's already a feature that defined "the one field that matters, even if there are extra ZST markers":repr(transparent). (That probably doesn't work if every field is a ZST, butDerefto a ZST feels like an uncommon enough scenario that it doesn't worry me.)FromI'm more torn about. If one can deriveFrom, it feels like one should also be able to deriveInto, but that's something we tell people not to implement (if possible). So what I really want for a newtype that has an invariant isInnerFromSelf, but that feels meh.I remember seeing "we should have explicit support for declaring a newtype" expressed before, but can't seem to fine it...
iitalics commentedon Jun 29, 2017
Deriving
Fromautomatically derivesInto. If I recall correctly, you get an error if you attempt to deriveIntoyourself. I don't see the problem there.mark-i-m commentedon Jul 1, 2017
@scottmcm I think deriving
Fromis enough;Intowill be auto-impled (as @iitalics pointed out). But I do like the idea ofInnerFromSelfexcept maybe it makes more sense asIntoInnerinstead.fadeevab commentedon Mar 9, 2020
There is a
derive_derefcrate with ~68000 downloads for now, and I believe this is a good evidence that#[derive(Deref)]is in demand.Personally I've been implementing a trivial
Derefeach time for a newtype, where I use newtype construction for a flow control between interfaces rather than for hiding an internal representation.Lokathor commentedon Mar 9, 2020
The fact that a crate can already reliably do this and also the fact that this isn't an essential part of letting the ecosystem pick a "standard" datatype for something means that this seems like a low priority.
Not that I'm against the idea, but if there's already a crate for it, what does putting it into
coregain us?Pauan commentedon Mar 9, 2020
@Lokathor That same argument can be made for all of the built-in derives in Rust.
Ixrec commentedon Mar 9, 2020
It would be interesting to survey the uses of derive_deref. In particular, how many of its uses are "real" Derefs as opposed to using Deref as a workaround for the lack of delegation.
It's also not clear to me that "If the type of that field is a reference, the reference will be returned directly." is the correct default behavior for Deref impls in general.
Unfortunately I don't have the time myself to investigate either point.
burdges commentedon Mar 9, 2020
Yes, I'd worry that
#[derive(Deref)]encourages deref polymorphism, which bring subtle problems. At least the variance issues should not be problematic here, right? I supposeDeref/DerefMuthave some history with soundness bugs too, but again not with such simple derives probably.I think rust should first sort out both (a) delegation in general and (b) convenient newtype delegation across many traits. I think (b) could reasonable precede (a) if done properly outside std/core, like maybe the newtype_derive crate, but convenient precise arithmetic,
Fn, etc. delegation should be preferred overDeref/DerefMut.Also, there is a units crate if you want units, so maybe even arithmetic traits should always omit some functionality for newtypes.
fadeevab commentedon Mar 9, 2020
@burdges
In my opinion, I'd worry that the existence of
Dereftrait itself encourages deref polymorphism, not the existence of #[derive(Deref)] implementation ;)Kind of, it doesn't stop anyone to implement a little boilerplate
impl Deref for MyType, and it doesn't stop using external crates implementingDeref.Yes, agree, if I understand you correctly. I think that seems like newtype could be a main motivation to have a quick
#[derive(Deref)]over it. By the way, derive_deref works with limitations that the struct should have only a 1 field (newtype).loganmzz commentedon Mar 8, 2025
Because Rust is promoting Zero-cost abstraction and an auto
Derefimpl (aka derive) is just a continuation of this promotion?Lokathor commentedon Mar 8, 2025
I would generally say that a newtype should implement
AsRef<Inner>instead ofDeref<Target=Inner>so that going to the wrapped type is an explicit step. Otherwise, why are you wrapping the inner value at all.As to From, that seems reasonable at first, but if there's no guards or checks on the inner value at all, why is the inner field private? If it's a public field you don't really need the From impl.
So it's not that more derives couldn't be in
core, but we would probably want stronger motivation for additionalcorederives. Since derives can be provided via a crate, the bar for adding them tocoreis relatively high.loganmzz commentedon Mar 8, 2025
Yeps,
Fromis open for discussion while I still see some reason to give some facilities for wrapper types. It might have complex situations, especially the fact thatFromcan be implemented for many "variants"."
Derefcoercion" is (for me) part for zero-cost abstraction and motivation for aDerefderive. As it can have only one implementation ofDereftrait for a struct, it sounds "easier". Especially for singleton tuple. I suppose it must not differ too much thanDefaultderive (in its logic).Lokathor commentedon Mar 8, 2025
The common meaning for "zero cost abstraction" is that it's a "zero runtime overhead abstraction". Writing
&xand activating Deref orx.as_ref()and activating AsRef would both satisfy this definition. It's a matter of how explicit we have people be.If you're bothering to use newtypes to enforce better typing on your expressions, you probably want to have more explicit changes between those types.
FalkWoldmann commentedon Jun 23, 2026
For future readers: Please see these related RFCs for the proposed changes:
Deref- Addderive(Deref)RFC #3911From(merged) - RFC: enablederive(From)for single-field structs #3809