<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4" -->

---
title: Four levels of in-place initialization | daily.dev
description: An in-depth proposal argues that Rust's in-place initialization problem should be solved not with a single feature but with a four-level hierarchy: raw...
canonical: https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Four levels of in-place initialization | daily.dev
og:description: An in-depth proposal argues that Rust's in-place initialization problem should be solved not with a single feature but with a four-level hierarchy: raw...
og:url: https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4
og:image: https://api.daily.dev/og/posts/rZ5EXPDp4.png
og:image:alt: Four levels of in-place initialization
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Four levels of in-place initialization

**[Lobsters](https://daily.dev/sources/lobsters)** · 7 min read · 0 upvotes · 0 comments

## Summary

An in-depth proposal argues that Rust's in-place initialization problem should be solved not with a single feature but with a four-level hierarchy: raw pointers with MaybeUninit (most flexible, unsafe), a proposed &uninit/&own reference pair for safe first-class uninitialized places, 'placing functions' that rewrite return to write into an out-pointer without changing function signatures, and automatic MIR-level move elimination (an optimization, not guaranteed semantics) as proposed in RFC 3943. The piece walks through code examples for each level, compares their expressivity, safety, signature impact, and semantic guarantees, and concludes that Rust should offer complementary high-level and low-level primitives rather than one universal mechanism, similar to how const works today.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://blog.yoshuawuyts.com/four-levels-of-in-place-initialization>

## Questions this post answers

### What is the &uninit/&own reference proposal in Rust for in-place initialization?

It is Ding Xiang Fei's proposal for a reference pair that makes uninitialized places first-class and safely checkable by the compiler. A programmer takes an &uninit reference to an uninitialized value, initializes its fields, and once complete the reference is notarized into an &own reference confirming full initialization, all without unsafe code.

_daily.dev surfaces deep design discussions like this for developers tracking Rust's evolving memory model._

### What does RFC 3943 propose for Rust with MIR move elimination?

Authored by Amanieu, RFC 3943 proposes that the compiler automatically eliminate moves at the MIR level as a performance optimization. Unlike placing functions, this behavior is not guaranteed semantics, only a best-effort optimization, so returning !Move types from a MIR-move-eliminated function would still be disallowed since the elimination is an implementation detail rather than a language guarantee.

_developers evaluating Rust compiler proposals can follow debates like this one via daily.dev._

### What are placing functions in Rust and how do they achieve in-place initialization?

Placing functions rewrite the return keyword so a function writes its result directly to an out-pointer instead of copying it, avoiding extra moves. They can be implemented using raw pointers or &uninit/&own references but require no changes to the function signature, and a proposed emplace effect would let such functions safely return address-sensitive, non-movable (!Move) types.

_track proposals like placing functions on daily.dev while deciding how Rust APIs should handle emplacement._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 10 comments across lobsters, hackernews (as of 2026-09-14).

**TL;DR:** Technical discussion largely tries to parse and clarify the author's proposal, with commenters generally agreeing that guaranteed optimizations (Level 3/move elimination) are less desirable than explicit, developer-controlled constructs, while debating the finer details of the &uninit/&own reference design.

**Sentiment:** 15% positive · 70% mixed · 15% skeptical

**The case for**

- Some note that guaranteed compiler optimizations aren't unprecedented, pointing to C++'s guaranteed copy elision as a working precedent.
- Detailed technical replies clarify why a native &uninit reference type with field projections and unique-invariant lifetimes would be more sound than reusing &mut MaybeUninit patterns.

**The pushback**

- Multiple commenters argue relying on an unguaranteed compiler optimization (Level 3) is risky compared to explicit language constructs that let developers enforce the behavior.
- One commenter points out that a naive &mut MaybeUninit<A> -> &mut A approach doesn't actually prove that the original place was initialized and can lead to memory leaks or unsoundness with pinning.

**By community**

- lobsters (mixed): Commenters mostly seek clarification on the four-level hierarchy and debate whether guaranteed move elimination is safe to rely on, with deep technical back-and-forth on reference-based alternatives.
- hackernews (mixed): No substantive comments were provided to characterize the discussion.

**Hottest debate:** Whether automatic move elimination should ever be relied upon as guaranteed behavior versus treated strictly as an optional optimization.

**Open questions**

- Is there a practical difference between a plain &mut MaybeUninit<A> -> &mut A pattern and the proposed &uninit/&own reference types?
- How would a debugger handle Rust's unspecified ABI when placement-style returns are optimized differently per call site?

**Highlights**

> > Similarly, if instead of &uninit/&own (I think this is the proposal?) ... The most recent (I think - I wrote it some months ago) proposal / phrasing of the feature is in our combined beyond-refs wiki: https://rust-lang.github.io/beyond-refs/in-place-init/uninit-ref.html > ... I couldn't see why we can't have ... is there a practical difference between the example above and the added-syntax version? The compiler needs a way to "see" we init-ed all of A's fields, and it could allow us to convert a &mut for a &mut? Yes; it's exactly this and a bit more: with MU you (currently, until we have field projections) cannot project from `MU<Struct>` to `MU<Field>`, and the compiler cannot reason about the initialisation status of the data, especially if we want to perform initialisation in a different function. In particular, the `&mut MaybeUninit<A>` and its resulting `&mut A` are not necessarily related to each other: the lifetime does mean that the compiler cannot reuse the `MaybeUninit<A>` before the `&mut A` is dropped, but they may not point to the same memory. For instance your `init_a` could return a `&'static mut A` created from a `Box::leak(Box::new(A { ... }))`. Hence, the compiler cannot use this function's return value as proof of `x: A` being initialised. Another issue is that when we drop the `&mut A`, the `A` is of course not dropped: this implies that we've leaked memory. That's not nice, and it may also lead to unsoundness if we eg. unsafely turn the `&mut A` into a `Pin<&mut A>` but fail to properly handle deallocation before exiting the scope. In general this means that the `init_a` function does not play well with pinning, and as a result it's not really useable for pin-initialisation. Fundamentally, the issue is that while `&mut MaybeUninit<A> -> &mut A`  gives us some lifetime safety, it's not strong enough to guarantee initialisation of the `MU<A>` (that requires an invariant lifetime), it's not versatile enough (some functions, f.ex. C++ constructors, do not return the out-pointer and instead simply imply that initialisation has happened), and it's not safe Rust: in the end it's probably better to just use raw pointers instead. A native `&'a uninit A` with a ZST init proof token `init<'a>` enables these: 1. If the `'a` lifetime is unique (the compiler must ensure this, this isn't too hard either) and the two types are invariant on `'a` then this is strong enough to guarantee that not only some value has been initialised but that it was exactly this `A`. 2. Because we can determine that exactly our `let mut x: A` was initialised, we can leave the world of references and go from an `&uninit A` into an initialised `x: A`: this should (hopefully) make it easier to then safely Pin it. 3. A native reference type gives us the possibility to use field projections (without waiting for the field projections work to finish). This gives us good ergonomics. 4. Functions that imply initialisation can return `init<'a>` directly, while functions that return an initialised out-pointer can easily return a `struct InitPtr<'a, T>(&'a uninit T, init<'a>)` that acts as both the out-pointer and proof of its initialisation at the same time: this type can be dropped normally (the `init<'a>` proof token cannot be dropped at runtime as it cannot find the `T` to drop since it does not hold a pointer). It is versatile enough to enable both basic patterns. 5. Most importantly: because we have field projections and the unique-invariant lifetime, the compiler can track initialisation status field by field: this means that unsafe is not needed at all.
> — [aapoalas on lobsters · 4 points, 1 comments](https://lobste.rs/s/snhfrq/four_levels_place_initialization#c_dz5oau)

> Level 3 is about hoping for an optimization vs expressing requirement. The same applies to tail call support vs tail call elimination as an optimization, where if you're writing recursive algorithms, you want to be able to *guarantee* that tail calls get eliminated.
> — [hjvt on lobsters · 5 points, 1 comments](https://lobste.rs/s/snhfrq/four_levels_place_initialization#c_nv8nkz)

> Notably, C++ does have a guarantee that more or less this exact optimization has to happen, it's called "guaranteed copy elision". So there's nothing fundamental that prevents a language from making hard guarantees about optimizations even when those are not explicitly requested by some extra piece of surface syntax. There are of course tradeoffs. Guaranteed copy elision being something that happens implicitly when certain conditions are met means it can be somewhat fickle and the compiler will not help you if you accidentally invalidate it.
> — [muvlon on lobsters · 1 points](https://lobste.rs/s/snhfrq/four_levels_place_initialization#c_devs15)

> I'm trying to understand the author's position. It SOUNDS to me like they are saying that:  * "Level 0: Raw pointers" already exists and should continue to exist  * "Level 1: References" is something they support adding as a "low level" feature  * "Level 2: Placing Functions" is something they support adding as a "high level" feature  * "Level 3: Automatic Move Elimination" is something they advise against adding Can any other readers (or the author) comment on whether you think I interpreted it correctly?
> — [mcherm on lobsters · 3 points, 2 comments](https://lobste.rs/s/snhfrq/four_levels_place_initialization#c_niket0)

**Source threads**

- [lobsters](https://lobste.rs/s/snhfrq/four_levels_place_initialization) · 16 points · 10 comments
- [hackernews](https://news.ycombinator.com/item?id=49312903) · 3 points · 0 comments

## Similar posts on daily.dev

- [Upcoming Rust language features for kernel development](https://daily.dev/posts/upcoming-rust-language-features-for-kernel-development-qkl4smo7p) · Hacker News · 12 upvotes · 0 comments
- [Move, Destruct, Forget, and Rust · baby steps](https://daily.dev/posts/move-destruct-forget-and-rust-baby-steps-xwxiulp3v) · Lobsters · 14 upvotes · 1 comments
- [Practical Rust API Design](https://daily.dev/posts/practical-rust-api-design-qwmqrnfyi) · corrode · 49 upvotes · 7 comments

---

Tags: [#rust](https://daily.dev/tags/rust), [#language-design](https://daily.dev/tags/language-design)

[View this post on daily.dev](https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Four levels of in-place initialization","url":"https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4"},"datePublished":"2026-08-18T03:32:55.342Z","dateModified":"2026-09-14T07:07:00.788Z","description":"An in-depth proposal argues that Rust's in-place initialization problem should be solved not with a single feature but with a four-level hierarchy: raw...","image":"https://media.daily.dev/image/upload/s--0_ODbtD2--/f_auto/v1722860399/public/Placeholder%2008","thumbnailUrl":"https://media.daily.dev/image/upload/s--0_ODbtD2--/f_auto/v1722860399/public/Placeholder%2008","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"rust,language-design","timeRequired":"PT7M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"Four levels of in-place initialization"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/four-levels-of-in-place-initialization-rz5expdp4#faq","mainEntity":[{"@type":"Question","name":"What is the &uninit/&own reference proposal in Rust for in-place initialization?","acceptedAnswer":{"@type":"Answer","text":"It is Ding Xiang Fei's proposal for a reference pair that makes uninitialized places first-class and safely checkable by the compiler. A programmer takes an &uninit reference to an uninitialized value, initializes its fields, and once complete the reference is notarized into an &own reference confirming full initialization, all without unsafe code. daily.dev surfaces deep design discussions like this for developers tracking Rust's evolving memory model."}},{"@type":"Question","name":"What does RFC 3943 propose for Rust with MIR move elimination?","acceptedAnswer":{"@type":"Answer","text":"Authored by Amanieu, RFC 3943 proposes that the compiler automatically eliminate moves at the MIR level as a performance optimization. Unlike placing functions, this behavior is not guaranteed semantics, only a best-effort optimization, so returning !Move types from a MIR-move-eliminated function would still be disallowed since the elimination is an implementation detail rather than a language guarantee. developers evaluating Rust compiler proposals can follow debates like this one via daily.dev."}},{"@type":"Question","name":"What are placing functions in Rust and how do they achieve in-place initialization?","acceptedAnswer":{"@type":"Answer","text":"Placing functions rewrite the return keyword so a function writes its result directly to an out-pointer instead of copying it, avoiding extra moves. They can be implemented using raw pointers or &uninit/&own references but require no changes to the function signature, and a proposed emplace effect would let such functions safely return address-sensitive, non-movable (!Move) types. track proposals like placing functions on daily.dev while deciding how Rust APIs should handle emplacement."}}]}
```

