-
Notifications
You must be signed in to change notification settings - Fork 110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C-DEREF contradicts idiomatic API in the standard library #249
Comments
My impression was that this newtype Deref pattern was mostly a hackaround for the lack of a proper "delegation" feature (or https://crates.io/crates/ambassador). Unfortunately I've forgotten most of the details since the last time this was thoroughly discussed, so I might be completely off-base here for state-of-the-art Rust, but: I believe the main limitations are that this does nothing for delegation use cases beyond a simple newtype, and even with a simple newtype it can quickly lead to ambiguity and messy error messages if there's a method name collision somewhere or just too many refs and derefs happening in close proximity (though, again, this may be out of date; I don't recall any concrete examples). I wouldn't be surprised if it's the least bad option for some newtypes, but IIRC it was one of those solutions that "works until it doesn't" and usually has a more robust alternative. |
FWIW, the ship has long since sailed on "only smart pointers deref". Stable std counterexamples:
Unstable std: Big name library counterexamples:
If your newtype is transparent (that is, not repr, but that However, I should note that this doesn't override the " Or IOW, don't If it were up to me, we should strike C-DEREF (to avoid confusion/misleading advice) or reword it to be more about "don't introduce methods that could clash" (or IOW act like a smart pointer, even if it's into the exact same memory location) than "be a smart pointer". (And of course, guidelines are meant to be bent when they don't apply as directly. I think the important thing is to realize when you impl |
This sounds similar to C-SMART-PTR. |
AssertUnwindSafe and ManuallyDrop examples convince me that the current guideline as stated is clearly wrong/misleading, and that we need to do something about this. |
Minor note: This is because it wraps In any case, both C-DEREF and C-SMART-PTR I think are aimed much more strongly at generic I think I'm personally fine with
For example, consider a type which implements |
Also, I'd just like to note that C-DEREF says that I think C-DEREF can stick around in a more clear fashion, which doesn't just say "only for smart pointers" but instead acknowledges the implicit meanings of |
The ship has flown the nest; `Deref` is not exclusively for smart pointers anymore. Fixes rust-lang#249, the direct contradiction of C-DEREF with idiomatic std APIs.
I've PRd #251 as a smaller rewording which should be fairly unobjectionable. |
The book also encourages implementing |
C-DEREF unambiguously says that Deref is only for smart pointers. However I've noticed (via this tweet) that there's another case where I reach out for Deref. It's not immediately clear to me who is wrong, the API guidelines or my code, so I am raising this issue to figure this out!
EDIT: #249 (comment) gives much better examples
I often implement Deref for newtype struct pattern -- when the struct has a single field, and exists to enforce some static invariant. A good example here is MainfistPath type from rust-analyzer, which is a wrapper around
Path
which guarantees thatparent
is not-None. I implementDeref
here becauseManifestPath
is aPath
, and I want to get all the methods for free.Another case is somewhat more obscure, and relates to this code. There, I have a hashbrown hash map of Nodes, but I use the raw API to supply my own, custom Hash. The code currently has a bug where, in one place, default hash impl is used, because
Node: Hash
. I want to do the following:Again, the reasoning here is that I wrap the type as is, and it would be convenient to get access to all the methods for free.
I suggest focusing on the first case, at it seems more representative to me:
Some specific questions:
ManifestPath
is not a smart pointer, but my definition of smart pointer might be wrong.Deref
impl? I personally don't see any (not to say that there aren't any)Quick googling showed one post wich says you can implement Deref for newtypes (cc @JWorthe): https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html
The text was updated successfully, but these errors were encountered: