Re:Mistakes with Rust smart pointers: when Deref goes wrong
by dathinab on Monday July 10, 2023 @12:59PM
(#36669199)
As a side note, rust does not have inheritance, at not point did `AsciiString` inherited the `Index` implementation through `Deref`.
What happened is that in many usages the compiler would insert an implicit deref which would lead to an `Index` implementation being available.
But this does not work in all cases. Not just the case mentioned in the article but many others. The simplest is that it doesn't implement the `Index` trait and hence any generic bound requiring `Index` will fail if you try to use it with a `AsciiString`.
So it important to _not think of `Deref` as a form of inheritance ever_ nor use this as a oversimplifications when teaching rust or similar, it will only lead to a lot of confusion.
Additionally smart pointer in rust are "pointer like" which means you don't expect them to have methods by themself or anything like that. Hence why special methods on smart pointers are implemented as static function on the type, instead of methods.
Through `Deref` can also idiomatically be implemented for types with a owned/borrowed duality (e.g. `String`/`&str`) so `AsciiString/AsciiStr` would work but `AsciiString/str` won't be ideomatic.
Then if you idiomatically implement traits on this types you won't run into the issue described in the post, as you implement all you `Index` types and similar on the `&AsciiStr`/`&mut AsciiStr` etc.
Anyway there is a way to get a reference to a different kind of type, e.g. getting a `&str` from a `AsciiString`. It's `AsRef`. But that is not automatically applied like `Deref` for the reasons many reasons including stuff like mentioned in the Article.
Lastly a better way to think about why it doesn't work is that the type resolver looks if the type is implemented on your concrete type in some form and only if it isn't it will potentially dereference. And due to technical details of how type resolving reliable in multiple direction can be tricky `Index<T>` does count here as "the type is implemented" even if the `T` doesn't match.
The articles conclusion of not implementing `Deref` (in most cases) is something I can fully agree with.
What happened is that in many usages the compiler would insert an implicit deref which would lead to an `Index` implementation being available.
But this does not work in all cases. Not just the case mentioned in the article but many others. The simplest is that it doesn't implement the `Index` trait and hence any generic bound requiring `Index` will fail if you try to use it with a `AsciiString`.
So it important to _not think of `Deref` as a form of inheritance ever_ nor use this as a oversimplifications when teaching rust or similar, it will only lead to a lot of confusion.
Additionally smart pointer in rust are "pointer like" which means you don't expect them to have methods by themself or anything like that. Hence why special methods on smart pointers are implemented as static function on the type, instead of methods.
Through `Deref` can also idiomatically be implemented for types with a owned/borrowed duality (e.g. `String`/`&str`) so `AsciiString/AsciiStr` would work but `AsciiString/str` won't be ideomatic.
Then if you idiomatically implement traits on this types you won't run into the issue described in the post, as you implement all you `Index` types and similar on the `&AsciiStr`/`&mut AsciiStr` etc.
Anyway there is a way to get a reference to a different kind of type, e.g. getting a `&str` from a `AsciiString`. It's `AsRef`. But that is not automatically applied like `Deref` for the reasons many reasons including stuff like mentioned in the Article.
Lastly a better way to think about why it doesn't work is that the type resolver looks if the type is implemented on your concrete type in some form and only if it isn't it will potentially dereference. And due to technical details of how type resolving reliable in multiple direction can be tricky `Index<T>` does count here as "the type is implemented" even if the `T` doesn't match.
The articles conclusion of not implementing `Deref` (in most cases) is something I can fully agree with.