SE-0400: Init Accessors

I've had to spend considerable effort working around it without requiring non-compiler-generated conformance on the enclosing types; there's a lot of JSON out there that uses "missing" as a space/bandwidth-saving synonym for explicit null. It's why IkigaJSON has NilValueDecodingStrategy, and why Fluent's handling of Codable has ugly workarounds involving superDecoder(forKey:).


So for using this proposal already; it takes an existing concept and breaks it apart into composable pieces. That decomposition lets us more generally approach problems and does not special case property wrappers. The spelling settled on seems quite reasonable and feels natural with the surrounding components.

This definitely addresses the problem scope well and lets other systems build on top of a more generalized system.

I have read the review threads, the proposal and used the feature in the development of another feature (Observation).

I feel like this will open up some new designs, but those will be considerably cleaner than the alternatives. Primarily this seems to me like an absolute MUST for macros that interact with types and generate fields.


Taking off my review manager hat for a moment, I have a few thoughts/questions:

  • I agree with @DevAndArtist's comment from the pitch thread:

  • I still don't like the restriction that the ability to synthesize a memberwise init depends on the relative ordering of properties and their accesses clauses. Since accesses clauses can only refer to stored properties there's no chance of cycle, and IMO we should synthesize a memberwise init with the parameters matching source order but with properties initialized in dependency order (ties broken by source order).

  • To Jordan's point above:

    is there a reason that we must support this (init accessors which don't actually initialize anything)? It doesn't seem necessary for subsuming property wrappers, so I'm curious if we just ought to leave it out. It seems somewhat esoteric. But if there's a super compelling use case I'd love to hear it! (E.g., is this support necessary for Observable?)


  • Does invoking the setter of a stored property in an init accessor (can you do this?) invoke the didSet observer? IIRC the current rule is that setters called inside init never call didSet, seems like we should extend that to init accessors.

I noted myself as weakly against this direction in the pitch, but I think one thing to consider with the new syntax that puts the initializes and accesses clauses outside the init clause, a future direction which allows combining the init and set accessors is IMO significantly more awkward (it's not clear that initializes really only applies to the init and not the set). I guess you could just learn this, but it's something to consider...


No, we can't invoke the didSet observer, because observers have access to all of self


Yeah, I'm thinking of cases where it would be (dynamically) valid to call didSet, similar to:

struct S {
    var x: Int {
        didSet {
    var y: Int

    init() {
        self.x = 0
        self.y = 0
        self.x = 0

    mutating func f() {
        self.x = 0

S() // only prints `didSet` once

I was imagining that you need to write @inlinable on the init accessor explicitly in order to use it from an @inlinable initializer, but I can see how the proposal is totally not clear about that!

The implied parameter is called newValue, which is deliberately consistent with set. The reason to use newValue instead of initialValue is because the word "new" still fits with initialization; you are indeed providing a new value to the field when you are initializing it. I also wanted to avoid adding another magic parameter name that people need to discover and then remember. I don't really see a strong motivation to introduce initialValue instead of newValue here.

init accessors don't interact with synthesized conformances at all. Those conformances still look specifically at the set of stored properties. It's plausible that the generated conformance could use the same strategy that member-wise initializers have in this proposal, but that would be a semantic change to the way property wrappers behave today. However, this feature might allow you to write Codable conformance synthesis through a macro that has the behavior you're after, where the conformance is based on the "original" stored properties as written (e.g. before any property wrapper or macro transformations happen).

I don't think init accessors are any more special than get and set accessors.

It's not necessary for @Observable, which backs every computed property by a stored property. The dictionary storage example in the proposal is a proxy for use cases that back all properties by some external storage mechanism, such as @Model from SwiftData or the Realm use-case mentioned at the end of the SE-0385 motivation:

Consider the Persisted property wrapper from the Realm package:

@propertyWrapper public struct Persisted<Value: _Persistable> { ... } 

class Dog: Object { 
  @Persisted var name: String 
  @Persisted var age: Int 

To support advanced schema customization, the property wrapper could store a string that provides a custom name for the underlying database column, specified in the attribute arguments, e.g. @Persisted(named: "CustomName"). However, storing this metadata in the property wrapper requires additional storage for each instance of the containing type, even though the metadata value is fixed for the declaration the property wrapper is attached to. In addition to higher memory overload, the metadata values are evaluated eagerly, and for each instantiation of the containing type, rendering property-wrapper instance metadata too expensive for this use case.


Combined with attached macros, the @Persisted property wrapper in Realm can evolve into a macro attached to persistent types, combined with custom metadata attributes that provide schema customization for specific declarations

I believe these use-cases really do want diagnostics in the case where you forget to assign to one of the computed fields in an initializer.

Ah, we totally could make this work using the same strategy in definite initialization that chooses between an init accessor call or a set accessor call, but this proposal does not include this change. However, if an assignment to a computed property in an initializer is re-written to a set accessor call and that set accessor assigns to a stored property, the observer for that stored property will indeed be called (this is not new behavior in this proposal). But inside of an init accessor, property observers are never called.

1 Like

You might be right. It really depends from which angle we see it.

My arguments would be:

  1. init is different from getter and setter because it participates the type initialisation process.
  2. this syntax will leave getter and setter syntax untouched, which mean even we have init method, we can still return value without having to use get {}

But I agree it's true that this syntax is kind of alien to current Swift syntax. Same as the proposed init method :slight_smile:

Again, I fully support the idea. These are just syntax considerations. Thanks.


i think that this change is needed, altough it makes the language another bit more complicated, a direction that i know is needed by the necessities of us all, but i'm bit scaried of the risk of becoming "a gargantuan language" just like c++ with all this keyword and syntaxes

I just have a curiosity, this change would also enable apple engineers to resolve problems like the "core data requires that the not optional values should have a default value." when using SwiftData+CloudKit on the iOS17 Beta?

Assuming I'm understanding this proposal correctly, this is trying to solve the problem that you can't really do anything in an initializer without falling afoul of definite initialization rules, because the compiler doesn't "peer into" the implementation of what you call. Technically, what I would say is happening is that self is not fully initialized at the point of the thing you're trying to call, and the proposal is trying to specify a way to hand around a partially constructed object by explicitly specifying which parts of self it is allowed to touch and which parts it initializes.

The reason I describe this so generally is that the proposal seems to have a motivating example of property wrappers/macros, but I don't actually think property wrappers are the most common gap where something like this is needed. Instead, it looks something like this:

struct Foo {
	enum Bar {
		case a(A)
		case b(B)
	let bar: Bar
	let common: SomethingInCommon

	init(a: A) {
		bar = .a(a)

	init(b: B) {
		bar = .b(b)

	func commonInit() {
		common = doSomeCommonInitialization()

This doesn't work today, of course: you can't can't factor out the common parts of initializers because you can't call anything on self yet, and the other functions aren't allowed to initialize read-only members anyways. This new proposal does actually give a spelling to this pattern, but it reads pretty poorly, probably something like this:

var _commonInit: Void {
	init initializes(common) {
		common = doSomeCommonInitialization()

	get { fatalError() }
	set { fatalError() }

Obviously, this is because we're abusing a feature built for computed properties to do more general initialization. I think what this really shows is that the need here goes beyond just properties. To that end, I would like to see consideration of the concept of "this block of code accesses these fields and initializes some other fields, and is morally kind of operating as if it was part of an initializer" rather than "this property wrapper accesses these fields and initializes some other fields, and is morally kind of operating as if it was part of an initializer". It may be that we decide that we want to start with property wrappers for now and punt the more general version to future directions, but I do think it is important that even if we do that the syntax we pick now has a natural extension to this more general case should we choose to implement it at some point.


Yes. That issues comes from the Observation macro. If you use = … inside an init from an observable type, that means that you're calling the computed property and not really initializing the stored property. That's why this feature would resolve the problem as the Observable macro would start synthesizing the init accessors to properly reroute such assignments via the computed properties to their baking storage.


The last development snapshot available for download is from June 7. it would be great to have most recent one with this experimental feature available.

+1 from me.

A memberwise initializer will not be synthesized if a stored property that is an accesses effect of a computed property is ordered after that computed property in the source code:

This limitations seems artificial. Compiler should be able to compute topological sorting of the initializations. Or am I missing something? But that's a really minor thing. If it comes with a noticeable performance hit, I'd rather manually reorder property declarations once, than have increased compilation times on every build.

Do I understand correctly that initializes and accesses can list only stored properties?

That is a bit unfortunate. The feature itself attempts to provide abstraction over initializing stored vs computed properties, but in this aspect abstraction is leaking - when initializing property inside init accessor one needs to know if it is a stored or computed property. Does macro API allow to query that and obtain a list of properties in the effects?

1 Like

Great, this is exactly the extension I’d expect of the current “never call observers from assignments that are lexically within an init” rule.

I am not ignoring you. I incorporated your capture-list-style syntax suggestion, along with the other suggestions at the end of the pitch thread, into the Alternatives Considered section, and I already justified (twice) in the pitch thread why we cannot simply infer initializes and accesses.


When the init accessor initialize all of self, is initializes(self) a valid spelling?

Because initializes and accesses are modeled as effects here, it seems plausible that a follow-up proposal could allow using those effects on instance methods. Those methods would then have the same semantics as init accessors - you cannot access all of self, you can only access the stored properties in the accesses list, and you must initialize the properties in the initializes list on all paths. There would be some other restrictions on where you're actually able to call those methods, and which other methods are allowed to be called from inside the implementation, but I don't believe anything in this proposal rules out this direction.


The problem with C++ isn't really the number of features, it's the number of features that both completely replace existing features while either having their design severely compromised for compatibility with prexisting features or being incompatible with those features in unpleasant and subtle ways. Often both.

All this plus WG21's bizarre fetish for making things that ideally would have some language support into library only features (std::optional, std::variant, std::forward & move, etc.).

Swift is a lot better about this because most of the new features (that aren't just sugar) don't really replace old features, tend not to have baffling interactions with existing features, and mostly only need to be known and understood by the person actually using the feature because Swift likes progressive disclosure.

Back on topic: It makes property wrappers less magic, but it's a bit verbose. I don't see a way to make it more concise without making it an unreadable mess, so I'm tentatively for this proposal. +0.5


Would it be feasible to add a didInit listener to a stored property, the same way one can add willSet or didSet without having to make it computed?

Maybe the initialized properties could be an effect similar to mutating/nonmutating in setters/getters. These modifiers declare how implicit self is passed. For instance, in a struct property's setter, self is passed as inout self by default. Similarly, if we generalize init to the initializing ownership modifier (similar to borrowing and consuming), self._initializedProperty would be passed as initializing _initializedProperty.

struct MyStruct {
  var _a: Int
  var a: Int { 
    nonmutating get { // Implies: `[borrowing self: Self] in`
    mutating set { // Implies: `[mutating self: Self] in`
      _a = newValue
    initializes(_a) init { // Implies:
       // `[initializing self._a: Int] in`
      _a = newValue

As for the awkwardness of the future direction combining the set and init implementations, we could just separate the accessors with a comma:

// ...
mutating set, initializes(_a) init { 
  _a = newValue
1 Like

@Jumhyn has made the same argument. Setting aside whether or not it's feasible, I think what's currently in the proposal leads to the most understandable behavior, because the order of the parameter list should match the order of initialization in the member-wise initializer (which I do not think we should change), which means that a change in dependencies could break all call-sites of your initializer. Topological sorting also just doesn't seem worth it the complexity to me. Do either of you have any use cases that would greatly benefit from this behavior?

That's correct. accesses fundamentally cannot list computed properties, because get accessors have access to self (unless we had this generalization of these effects). Perhaps initializes could be generalized to include computed properties with init accessors in the future.

initializes and accesses are part of the syntax tree, so a macro can gather all of the listed property names.

1 Like