# Using \`indirect\` modifier for \`struct\` properties

**URL:** <https://forums.swift.org/t/using-indirect-modifier-for-struct-properties/37600>\
**Category:** Pitches\
**Created:** [June 15, 2020, 4:11pm UTC](https://forums.swift.org/t/using-indirect-modifier-for-struct-properties/37600 "2020-06-15T16:11:30Z")\
**Posts on this page:** 1\
**Showing post:** 21

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [June 15, 2020, 6:25pm UTC](https://forums.swift.org/t/using-indirect-modifier-for-struct-properties/37600/21 "2020-06-15T18:25:46Z")

</div>

> [@anandabits](#):
>
> We can write `indirect enum` , not only `indirect case` . `@Indirect` does not work at the type level: it does not let us write `@Indirect struct` .

Sure, I'm aware of that—but if the user wants to put _all_ of their stored properties into heap-allocated space, I wonder if they're doing something where they would want finer control over that object and not have it hidden and inaccessible by the language. With enums, they don't have a choice unless they made their payload a class, but that would make the type itself harder to use because it would affect the pattern matching API, so I don't think the analogy _quite_ holds.

However, thinking about it further, I will grant that adding something like `@Indirect` to the standard library could cause users to easily enter into situations that result in poor performance—someone annotating multiple properties with `@Indirect` would incur one allocation per property, whereas native language/compiler support could potentially gather all of the `indirect` properties together into a single combined allocation. So that would be a big advantage to deeper integration.

One critical issue that hasn't been addressed here yet though is how mutation of `indirect` properties would be handled. This isn't a problem yet for `indirect enum`s or `indirect case`s because [enums can't be modified in place](https://forums.swift.org/t/in-place-mutation-of-an-enum-associated-value/11747/5), but `indirect` struct properties would **definitely** need to handle copy-on-write correctly for mutation.

Unfortunately, it turns out this is easy to get wrong even in a library-only property-wrapper-based version:

> [@eneko](#):
>
> No need to use `enum` for the property wrapper, this is what I had in the gist:
> 
> ```swift
> @propertyWrapper
> class Indirect<Value> { ... }
> 
> ```

This version doesn't handle copy-on-write correctly, because copying an instance of the `struct` copies the reference to the `class` but nothing ever checks it for unique-reference or copies it, so mutating the property in one `struct` instance causes the other instance to reflect the change. The `enum` variant doesn't suffer from this problem because it does `self`-reassignment upon mutation:

> **Wrapper implementations copied from posts above**
>
> ```swift
> @propertyWrapper
> enum IndirectE<T> {
> indirect case wrapped(T)
> 
> init(wrappedValue initialValue: T) {
> self = .wrapped(initialValue)
> }
> 
> var wrappedValue: T {
> get { switch self { case .wrapped(let x): return x } }
> set { self = .wrapped(newValue) }
> }
> }
> 
> @propertyWrapper
> class IndirectC<Value> {
> var value: Value
> 
> init(wrappedValue initialValue: Value) {
> value = initialValue
> }
> 
> var wrappedValue: Value {
> get { value }
> set { value = newValue }
> }
> }
> 
> ```

```swift
struct StructWithIndirectE {
  @IndirectE var property: Int = 10
}

struct StructWithIndirectC {
  @IndirectC var property: Int = 10
}

do {
  let original = StructWithIndirectE()
  var copy = original
  copy.property = 20
  print(copy.property) // 20
  print(original.property) // 10 (👍)
}

do {
  let original = StructWithIndirectC()
  var copy = original
  copy.property = 20
  print(copy.property) // 20
  print(original.property) // 20 (🔥🔥🔥)
}

```

---

_[View the full topic](https://forums.swift.org/t/using-indirect-modifier-for-struct-properties/37600)._
