# \[Blog\] Safe pinned initialization

**URL:** https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404
**Category:** language design
**Created:** [September 18, 2022, 6:28pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404 "2022-09-18T18:28:47Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)
#### Post date: [September 18, 2022, 6:28pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/1 "2022-09-18T18:28:47Z")

</div>

[Continuing](https://internals.rust-lang.org/t/safe-partial-initialization/16443) my efforts to try to remove `unsafe` from the [linux kernel's rust API](https://github.com/Rust-for-Linux/linux) to initialize a `Mutex<T>` (you heard me, initializing a `Mutex` is `unsafe`). I have discovered [this RFC](https://github.com/rust-lang/rfcs/pull/2884) for a feature called `placement by return`. It got me thinking, if it could be used to solve the pin initialization problem. While reading I noticed quiet a few issues that would need to be resolved in order for it to be useful and compiled these ideas into this blog post:

[https://y86-dev.github.io/blog/return-value-optimization/placement-by-return.html](https://y86-dev.github.io/blog/return-value-optimization/placement-by-return.html)

I would love to know what you think of this.

---

<div class="post-metadata">

### Author: ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)
#### Post date: [September 24, 2022, 11:35am UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/2 "2022-09-24T11:35:26Z")

</div>

Here is my newest blog post about safe pinned initialization:

[https://y86-dev.github.io/blog/safe-pinned-initialization/overview.html](https://y86-dev.github.io/blog/safe-pinned-initialization/overview.html)

---

<div class="post-metadata">

### Author: ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)
#### Post date: [October 3, 2022, 3:47pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/3 "2022-10-03T15:47:35Z")

</div>

Here is the follow-up post about my library and ways to turn it into a language feature:

[https://y86-dev.github.io/blog/safe-pinned-initialization/in-place.html](https://y86-dev.github.io/blog/safe-pinned-initialization/in-place.html)

---

<div class="post-metadata">

### Author: ![jrose](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jrose/32/9591_2.png) [@jrose](https://internals.rust-lang.org/u/jrose)
#### Post date: [October 3, 2022, 5:51pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/4 "2022-10-03T17:51:15Z")

</div>

This is neat, though I’m not yet sold on the `<-` syntax. One note I had was that I’m not sure you need Init _and_ PinInit. You say

> But because we do not want to force everyone to stay pinned after initialization, we create a new trait instead[.]

But that only applies to types that don’t implement Unpin, and the pinning guarantee only starts at the first pin anyway, not at construction. Given that, it seems like there are four cases to consider:

1. The init does not care whether the resulting data is pinned. This seems fine whether or not the result is produced as pinned, because the pinning guarantee starts when calling `Box::into_pin` or whatever.

2. The init relies on pinning, and the result is produced as pinned. This is also fine.

3. The init relies on pinning, but the result is returned unpinned, and the type is Unpin (like a plain `i32`). This is also fine by the definition of Unpin, though likely a bit weird; what was the point of relying on pinning during initialization? (This is also unlikely to come up in practice; a pin-agnostic initializer is way more likely for such a type, e.g. a length-prefixed string buffer.)

4. The init pins the data as part of initialization, and the result is returned unpinned, and the type is !Unpin. This is a bug and the library should prevent it.

Given this case analysis, I think it would be “safe” to say that you only need Init as a trait and that it must always uphold the pinning guarantees (unless the type is Unpin). If all you do is field-by-field initialization, that will be true automatically; if you do something funky with `this`, that’s on you, and no worse than the current implementation.

EDIT: using Unpin to guard non-pinned results does rule out one scenario that your current traits support: in-place construction of a !Unpin type that you nonetheless plan to move. I can’t think of when that would be important, though.

---

<div class="post-metadata">

### Author: ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)
#### Post date: [October 3, 2022, 7:40pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/5 "2022-10-03T19:40:12Z")

</div>

A couple of observations on the first half of the blogpost:

- I feel like the `T` and `E` generic parameter on the `Init` and `PinInit` traits could be associated types, it makes more sense if an initializer can initialize only one type and return only one type of error.

- You could add a blanket implementation of `PinInit` for any type that implements `Init`, this way you can both guarantee the invariant that `PinInit::pinned_init` calls `Init::init` and also reduce the boilerplate for the caller.

---

<div class="post-metadata">

### Author: ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)
#### Post date: [October 5, 2022, 4:43pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/6 "2022-10-05T16:43:07Z")

</div>

Thanks for the feedback!

> [@jrose](#):
>
> You say
> 
> > But because we do not want to force everyone to stay pinned after initialization, we create a new trait instead[.]
> 
> But that only applies to types that don’t implement Unpin,

I had an intermediate iteration where this library only had `Init`. I ultimately dropped it because

- `PinInit<T>` & `Init<T>` vs `Init<T: !Unpin>` & `Init<T: Unpin>` is a bit more verbose to understand. Especially if you are coming to pinning the first time, I think not having to worry about if the type implements `Unpin` or not (made more difficult by the fact that is an auto trait) is important. You can immediately see how the initializer is designed to be used.
- there might be (I have not been able to come up with one, but I also could not rule out the possibility) a usage where you need both `fn() -> impl Init` and `fn() -> impl PinInit<>`. So I thought I should keep it this way instead of changing in the future.

> [@jrose](#):
>
> and the pinning guarantee only starts at the first pin anyway, not at construction.

Also note that I want things like [inserting into a linked list at construction](https://github.com/y86-dev/pinned-init/blob/main/examples/linked_list.rs#L38) and that needs pinning _at construction_.

> [@SkiFire13](#):
>
> I feel like the `T` and `E` generic parameter on the `Init` and `PinInit` traits could be associated types, it makes more sense if an initializer can initialize only one type and return only one type of error.

It certainly makes more sense and I havent thought of that. On the other hand, it makes declaring an init function much worse ergonomically:

```rust
impl Thing {
    pub fn new() -> impl Init<ToInit = Self, Error = !> {
        ...
    }
}

```

I can also not specify `!` as the default for errors. I think keeping them as generics will not really be bad, because they are not really designed to be implemented. When you require a type to implement `Init`, you almost always also need the initialized type anyway, so I do not see an issue here. Tell me if this would improve something I havent mentioned.

> [@SkiFire13](#):
>
> You could add a blanket implementation of `PinInit` for any type that implements `Init`, this way you can both guarantee the invariant that `PinInit::pinned_init` calls `Init::init` and also reduce the boilerplate for the caller.

That is a great idea!

---

<div class="post-metadata">

### Author: ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)
#### Post date: [October 5, 2022, 6:44pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/7 "2022-10-05T18:44:04Z")

</div>

> **see also**
>
> > **[moveit](https://lib.rs/crates/moveit)**
> >
> > A library for safe, in-place construction of Rust (and C++!) objects
> 
> [https://mcyoung.xyz/2021/04/26/move-ctors/](https://mcyoung.xyz/2021/04/26/move-ctors/)
> 
> [https://mcyoung.xyz/2021/12/19/move-ctors-2/](https://mcyoung.xyz/2021/12/19/move-ctors-2/)
> 
> [![](https://img.youtube.com/vi/UrDhMWISR3w/maxresdefault.jpg "RustConf 2021 - Move Constructors: Is it Possible? by Miguel Young de la Sota") ](https://www.youtube.com/watch?v=UrDhMWISR3w)

(you linked that, but to make it easier to reach)

An interesting observation is that in-place construction is _very_ similar to `#[may_dangle]` and the dropck eyepatch. `#[may_dangle]` says that the only thing I do with `T` is drop it; in place initialization says that the only thing you do is move the value into place.

I think placement by return could be made to work, although I agree that the implementation probably looks like moveit and your constructors.

(The split to `PinInit` is important, as what `PinInit` is saying is that the place is pinned at construction like a C++ object is, whereas `Init` follows the normal Rust rules of not being initially address sensitive. In theory you could have `Init: PinInit` with `Init` being an empty marker trait that the ctor is address insensitive.)

---

<div class="post-metadata">

### Author: ![y86-dev](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/y86-dev/32/9867_2.png) [@y86-dev](https://internals.rust-lang.org/u/y86-dev)
#### Post date: [October 6, 2022, 2:11pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/8 "2022-10-06T14:11:52Z")

</div>

> [@SkiFire13](#):
>
> You could add a blanket implementation of `PinInit` for any type that implements `Init`, this way you can both guarantee the invariant that `PinInit::pinned_init` calls `Init::init` and also reduce the boilerplate for the caller.

Unfortunately that cannot be done due to `downstream crates may implement trait [...]`. So I think it needs to stay this way...

---

<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: [January 4, 2023, 2:12pm UTC](https://internals.rust-lang.org/t/blog-safe-pinned-initialization/17404/9 "2023-01-04T14:12:47Z")

</div>

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