# Running projects with crossover in method resolution and coercion ## Reborrowing What today's RFC prescribes enables the following ```rust= f.call(needs_reborrow()); // RFC allows reborrowing on the arguments ``` ```rust= // Unspecified needs_reborrow().call(); // RFC does not allow this yet ``` Method resolution already tries weaking the type - `&mut` weakend to `&`, in future also through `CoerceShared` - `*mut T` weakened to `*const T` - `Pin<..>`: reborrow `CoerceShared` interacts with method resolution, not `Reborrow`. ## Generic `Deref` `Container<OuterArgs...>` weakened to `Container<InnerArg...>` automatically. Want to leave space for this. Not pushing on it now. ## Autoref and Generalized Coercions ## Overloading ## Concerns over method probing time complexity ## Concerns over shadowing detection and good diagnostics Sometimes compilers can appear to be too smart. ## Concerns over language design idioms * Could end up not being the best tool for any one use case * Would lead users down the wrong path * Can be confusing from user perspective to use a type with different targets for Deref and Receiver (not sure) * Is this a short term workaround for evolving trait hierarchies / lack of projections that we won't be happy we added later? * *Ding: personally I do not think so; trait evolution is still very valuable, see its RFC for further motivations; RfL would also continue to pursue it for its own merit* To make it actionable: Would help to have a use case for the split that we don't see a better way to express using other features * Challenge: We never drew a boundary around what we wanted people to use arbitrary self types for; we never defined "antipatterns" or "non-goals". * What's the underlying philosophy of arbitrary self types? * What does it mean to have `T: Receiver<Target = U>`? * I think I can give some motivation and examples, in which a split arbitrary self types is useful and others considered misuses. ### The use-case matrix To break down the use cases, here is a matrix for us to explore. | | `T: Deref` is not desirable | `T: Deref` is desirable | |-|-|-| | `T: Receiver` is not desirable| :shrug: | :question:<sup>[1](#why-do-that)</sup> | | `T: Receiver` is desirable| `Pin<_>: Deref<_>` is only desirable in certain cases | Smart pointers (`Deref::Target == Receiver::Target`) and "contractual" containers <sup>[2](#encrypted-envelope)</sup>(`Deref::Target <> Receiver::Target`) | ### <a id="why-do-that" /> "Why would you do that?" According to [std doc](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html#implementors) we have the following types that under the current arbitrary self types rule automatically work as receivers, too. - [`std::vec::PeekMut`](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html#impl-Deref-for-PeekMut%3C'a,+T%3E) - [`AssertSafeUnwind<T>`](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html#impl-Deref-for-AssertUnwindSafe%3CT%3E) - [`DropGuard`](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html#impl-Deref-for-DropGuard%3CT,+F%3E) - [`&LazyLock<T, _>`](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html#impl-Deref-for-LazyLock%3CT,+F%3E) - Various lock guards from `Mutex`, `RwLock`, etc. I randomly sampled Rust users and asked what they thought. They saw some utility of making them into method receiving values, but the first reaction was usually: someone made a mistake here and the code shall not pass reviews. ### <a id="encrypted-envelope" /> Security motivated example, contractual containers An `EncryptedEnvelope<T>` type encapsulates a structured data `T` by encrypting its serialisation with authenticated data using an AEAD scheme. An intuition is that, one should allow `EncryptedEnvelope<T>` to work like a method receiver. ```rust pub trait SafelyValidate { fn consume(self: EncryptedEnvelope<Self>, transform: Transform<Self>) -> Result<(), AeadError>; } ``` It is also intuitive that `EncryptedEnvelope<T>` should implement `Deref` because it is a data container. We could allow that, except `Deref::Target` shall never be `T` **for security reasons**. An automatic encryption without validation is a security breach. Instead, only access to the raw ciphertext bytes for unprivileged cryptographic computation such as hashing would be allowed. ```rust impl<T> Deref for EncryptedEnvelope<T> { type Target = [u8]; // THIS SHALL NEVER BE `T` fn deref(&self) -> &[u8] { } } impl<T> Receiver for EncryptedEnvelope<T> { type Target = T; // But this is okay } ``` #### Why `Deref` is useful in the first place? `Deref` is useful under a different context when the valuation of the inner structural data type is oblivious to us, such as application of cryptographic routines to the encrypted envelope as a whole. For instance, if we would like to build a Merkel tree out of many encrypted envelopes, it would be sensible to treat them as a container of bytes. The exact information of inner type is irrelevant. After all, Merkel tree, like most other cryptographic constructions, works only on serialised data. Since access to the serialised data is high frequency in this context, it would be more ergonomic to expose it through Deref. Also in the eyes of networking and RPC protocol stacks, the type of the inner structural data type is oblivious to them, too. Their job is to serialise them further or send the bytes down the wire. I can imagine that working with these envelopes without `Deref` but with `.buf()` calls to extract the underlying buffer could become painful in this context. ### The philosophical question So far we have two major camps of intuition behind method receiving types. - `Box<_>`, `Rc/Arc<_>` and smart pointers - They are useful as method receivers because they fill in a void that `&self`/`&mut self` creates, which is the pointer management. - `Box<_>` asserts uniqueness and provides perks like `Box::leak` and partial initialisation. - `Rc/Arc<_>` allows shared reference "safely." - This is something that plain old `&[mut] self` does not offer and what makes smart pointers "smart." - Otherwise, it makes more sense to resort to `&self` if none of these advantages is taken. - Constrained/contractual containers - They define a protocol through which the inner "content" is allowed to be interacted with - `Pin<_>` promises that the memory address of the content is stable; with `pin-ergnomics` the access to the fields and methods shall be further constrained to honour this contract; - The previous examples encodes invariants that the use of the container satisfies certain safety requirements or asserts facts about the generic type, if exists. In other words, what expectation that we would like to evoke when a developer sees the following code? ```rust impl SomeType { fn method(self: SomeOtherType<SomeType>) { .. } } ``` It could be - `SomeOtherType<SomeType>` has a conceptual connection with `SomeType`, and - An important property or protocol on `SomeOtherType<_>` must be relevant or upheld, in order to call this subroutine. # Concern over complication of method probing ##### Qn. How would the adjustment work under reborrowing and generic `Deref`s, without arbitrary self types? ##### Qn. Can we develop mitigation and # Experiment and definition of success # AIs - Contact with original RFC authors