# Idea: DerefPin/DerefCell

**URL:** <https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292>\
**Category:** language design\
**Created:** [April 11, 2018, 7:34pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292 "2018-04-11T19:34:02Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 11, 2018, 7:34pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/1 "2018-04-11T19:34:02Z")

</div>

Currently, `Pin` offers the unsafe `map` method, which is safe to use when returning a `Pin` to a struct field or other interior pointer that preserves `Pin`'s constraints. There is the idea of a `#[derive]`-like macro to automatically generate safe accessor methods to make this nicer.

Similarly, `Cell` has [RFC 1789](https://github.com/rust-lang/rfcs/blob/master/text/1789-as-cell.md), which offers a safe conversion from `&Cell<[T]>` to `&[Cell<T>]`. This _should_ also apply to struct fields, but there’s no easy way to express this in the type system.

If `Pin<'a, T>` and `&'a Cell<T>` were part of the language, these operations could be built in. But that’s a lot of surface area to add to the language. What if we had something like `Deref` that applied to types like this, where `deref` returned a `*T` that the compiler would re-wrap in a `Pin`/`&Cell` after field projection or indexing? This could potentially be a much smaller language change to get the same ergonomic wins.

Could such a trait be shared between `Pin` and `&Cell`? At first glance it seems the two types of references can be projected into using the same rules. If not, it would need to be two traits, which is not much better than baking `Pin` and `&Cell` into the language.

Are there any other reference types that could take advantage of this? `&RefCell` might be able to use a wide pointer that keeps a reference back to its counter, but I’m not sure how useful that would be. Or is it too specific? I can imagine "`map` a field projection" working with `Option` or `Result` as well, where it wouldn’t be constrained by the same rules as `Pin`/`&Cell`.

Thoughts?

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [April 12, 2018, 5:42pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/2 "2018-04-12T17:42:56Z")

</div>

This sounds interesting! So essentially this would an an unsafe-to-implement trait that reference types could implement to declare that `Ref<'a, T>` where `T` is a struct with a public field `f` of type `U`, can be turned into `Ref<'a, U>` pointing to the field? Really this is a trait that wants to be implemented for type constructors (things of kind `Lifetime -> * -> *`), not types. I think this needs associated type constructors, and even then it remains somewhat awkward. Something like

```rust
trait AccessFieldField {
  type<'a, T> Ref;

  unsafe fn access_field<'a, T, U, F>(
    x: Self,
    map: F
  ) -> Ref<'a, U>
where
  Self = Ref<'a, T>,
  F: FnOnce(*const T) -> *const U;
}

```

(I know equality constraints are not a thing. Anyways.)

Then `x.field` would compile to `unsafe { x.access_field(|x| &(*x).field as *const _) }`.

> [@rpjohnst](#):
>
> Are there any other reference types that could take advantage of this?

`cell::Ref` and `cell::RefMut` come to my mind.

---

<div class="post-metadata">

**Author:** ![glaebhoerl](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/glaebhoerl/32/1978_2.png) [@glaebhoerl](https://internals.rust-lang.org/u/glaebhoerl)\
**Post date:** [April 12, 2018, 7:38pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/3 "2018-04-12T19:38:03Z")

</div>

Does the fact that one of them is a “pointee type” (`Cell`, which needs an `&` in addition to make it a reference) and the other is a “pointer type” (`Pin`, which is already a reference) not throw a wrench into the works?

(In an ideal world, maybe `&` and `&mut` themselves would’ve worked this way, instead of autoderef, forming a coherent story together with what we now call “default binding modes”.)

---

<div class="post-metadata">

**Author:** ![Centril](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/centril/32/3334_2.png) [@Centril](https://internals.rust-lang.org/u/Centril)\
**Post date:** [April 12, 2018, 9:05pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/4 "2018-04-12T21:05:50Z")

</div>

Could this be done via some auto-deriving mechanism instead?

I also wonder if it could / should apply to non-reference stuff but `arbitrary_self_types` cases such as:

> [@Forever immutable owned values](https://internals.rust-lang.org/t/forever-immutable-owned-values/6807):
>
> We have the concept of “exclusive” (or mutable) references &mut T in Rust. The only way to create value of that type in safe Rust is to (at some point) have a let mut foo: T = .. and then do &mut foo somewhere else. Owning a value and not marking that mut in let mut foo = make\_owned\_value(); does not mean that it is not possible to mutate it. All you have to do is to move foo and now you are allowed to mutate the moved foo. You can simply do this with: fn main() { struct Foo; fn make\_o…

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 13, 2018, 2:19am UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/5 "2018-04-13T02:19:42Z")

</div>

@RalfJung Hm, you're right- it does kind of call out for HKT. I wonder if, since it's already compiler magic, whether it would be worth just special casing it? Or if that would be too icky? Maybe split the reconstruction into a separate trait and have the compiler match them up on its own:

```rust
trait DerefField { // impl<'a, T> for Pin<'a, T>
    type T;
    unsafe fn deref_field(self) -> *const T;
}

trait RefField { // impl<'a, U> for Pin<'a, U>
    type U;
    unsafe fn ref_field(*const U) -> Self;
}

```

Despite the ickiness this _should_ work for both `Pin<'a, T>` and `&'a Cell<T>`, right?

> [@glaebhoerl](#):
>
> (In an ideal world, maybe & and &mut themselves would’ve worked this way, instead of autoderef, forming a coherent story together with what we now call “default binding modes”.)

😃 I've liked this idea since the current incarnation of default binding modes was worked out.

> [@Centril](#):
>
> Could this be done via some auto-deriving mechanism instead?

That would presumably wind up turning field access into method access, which is why I brought this version up to begin with.

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [April 15, 2018, 9:39am UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/6 "2018-04-15T09:39:38Z")

</div>

> [@glaebhoerl](#):
>
> Does the fact that one of them is a “pointee type” (Cell, which needs an & in addition to make it a reference) and the other is a “pointer type” (Pin, which is already a reference) not throw a wrench into the works?

I think the relevant type would be `&Cell<T>`, which _is_ a pointer. The fact that it is composed of two types should not be a problem, hopefully.

> [@rpjohnst](#):
>
> Maybe split the reconstruction into a separate trait and have the compiler match them up on its own:

Well but how exactly would the matching-up works?

Also, I was just reminded of the family pattern, and that could maybe even express the right trait without using equality constraints. However, I still have no idea how inference would work:

```rust
trait RefFamily {
  type<'a, T> Ref : Deref<Target=T>;
}

struct ShrRef;
impl RefFamily for ShrRef {
  type<'a, T> Ref = &'a T;
}

struct MutRef;
impl RefFamily for MutRef {
  type<'a, T> Ref = &'a mut T;
}

struct CellRef;
impl RefFamily for CellRef {
  type<'a, T> Ref = &'a Cell<T>;
}

struct PinRef;
impl RefFamily for PinRef {
  type<'a, T> Ref = Pin<'a, T>;
}

trait DerefField : RefFamily {
  unsafe fn access_field<'a, T, U, F>(
    x: Self::Ref::<'a, T>,
    map: F
  ) -> Self::Ref<'a, U>
  where
    F: FnOnce(*const T) -> *const U;
}

```

One would probably have to call this as `CellRef::access_field`, i.e. there would still have to be magic for determining the family when desugaring an `x.f`.

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [April 15, 2018, 5:23pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/7 "2018-04-15T17:23:08Z")

</div>

Some good points on the interaction of field projection with `Drop`, in the case of `Pin`, [here](https://github.com/rust-lang/rust/issues/49150#issuecomment-381387548) and [here](https://github.com/rust-lang/rust/issues/49150#issuecomment-381395895).

---

<div class="post-metadata">

**Author:** ![glaebhoerl](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/glaebhoerl/32/1978_2.png) [@glaebhoerl](https://internals.rust-lang.org/u/glaebhoerl)\
**Post date:** [July 9, 2018, 8:55pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/8 "2018-07-09T20:55:55Z")

</div>

If we’re not committed to having the sweetest possible auto-derefy syntax, we could just (“just”?) add a type for “field F in type T” – like C++ member pointers, basically, hopefully without their baggage (which IINM is mostly around member _function_ pointers) – and then each relevant type can just have an inherent method to apply the projection. We don’t need to give the type special syntax like C++ does, but it _would_ probably require language support for constructing instances of it (unless we can and want to hack it together with macros somehow, which, ick).

To illustrate:

```rust
pub struct Field<T, F> { offset: usize } 
// (it's an offset, not a size, but fields can't be at negative offsets)

impl<T> Cell<T> {
    pub fn field<F>(&self, field: Field<T, F>) -> &Cell<F> { ... }
}

impl<T> Pin<T> {
    pub fn field<F>(self, field: Field<T, F>) -> Pin<F> { ... }
}

fn example() {
    struct Example { x: i32, y: i32 }
    let cell = Cell::new(Example { x: 10, y: 11 });
    let cell_y: &Cell<i32> = cell.field(.y);
    // (not sure what the precise syntax should be here;
    // hopefully the compiler could apply some type-directed name resolution)
}

```

Notably, only the compiler could safely create instances of `Field`, so you can rely on it being “valid”.

(This could even allow some “mutable destructuring”, with dynamic checks – e.g. from `PinMut` you might want to get simultaneous sub-`PinMut`s to two disjoint fields. To support that, we could have an `fn` that takes two `Field`s (and returns two `PinMut`s) and asserts that the extent of the fields, as calculated from their offsets plus sizes\_of, don’t overlap. (Mere inequality checks aren’t enough, especially if we allow “deep” `Field`s into nested `struct`s: e.g. one could be to an outer `struct`, and another to its second field, overlapping without having the same offset.))

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 9, 2018, 9:12pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/9 "2018-07-09T21:12:23Z")

</div>

I actually spent a while thinking about this, here: [https://internals.rust-lang.org/t/pre-pre-rfc-field-offsets](https://internals.rust-lang.org/t/pre-pre-rfc-field-offsets)

I think a `Field<T, U>` (or as I called it, `T.U`) is the most elegant way to solve this annoying problem for “projectable” smart pointers (@Centril’s `Freeze<T>` would benefit from this too, as he points out in my thread).

---

<div class="post-metadata">

**Author:** ![rpjohnst](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rpjohnst/32/9524_2.png) [@rpjohnst](https://internals.rust-lang.org/u/rpjohnst)\
**Post date:** [July 9, 2018, 9:19pm UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/10 "2018-07-09T21:19:07Z")

</div>

That definitely isolates the compiler magic a lot more effectively than a `DerefField` trait would! I think the minimum we would need to start experimenting in a library (with a less-nice interface) would be `offset_of`, right?

---

<div class="post-metadata">

**Author:** ![mcy](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/mcy/32/6512_2.png) [@mcy](https://internals.rust-lang.org/u/mcy)\
**Post date:** [July 10, 2018, 5:57am UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/11 "2018-07-10T05:57:17Z")

</div>

Not even. You can do a bunch of gross things, though the dropck might decide to kill you. [https://play.rust-lang.org/?gist=864666d50278bccdb04857ac36ca9f36&version=nightly&mode=debug&edition=2015](https://play.rust-lang.org/?gist=864666d50278bccdb04857ac36ca9f36&version=nightly&mode=debug&edition=2015)

---

<div class="post-metadata">

**Author:** ![RalfJung](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ralfjung/32/2415_2.png) [@RalfJung](https://internals.rust-lang.org/u/RalfJung)\
**Post date:** [July 12, 2018, 10:31am UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/12 "2018-07-12T10:31:16Z")

</div>

However, for `Pin` at least we’d also like to support projecting through an `enum`, at which point offsets are not enough any more.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [March 25, 2019, 8:30am UTC](https://internals.rust-lang.org/t/idea-derefpin-derefcell/7292/13 "2019-03-25T08:30:03Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
