# Add shared storage to property wrappers

**URL:** <https://forums.swift.org/t/add-shared-storage-to-property-wrappers/49898>\
**Category:** Pitches\
**Tags:** propertywrapper\
**Created:** [June 24, 2021, 7:15pm UTC](https://forums.swift.org/t/add-shared-storage-to-property-wrappers/49898 "2021-06-24T19:15:27Z")\
**Posts on this page:** 1\
**Showing post:** 18

<div class="post-metadata">

**Author:** ![John\_McCall](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/john_mccall/32/1351_2.png) [@John\_McCall](https://forums.swift.org/u/John_McCall)\
**Post date:** [June 24, 2021, 10:36pm UTC](https://forums.swift.org/t/add-shared-storage-to-property-wrappers/49898/18 "2021-06-24T22:36:26Z")

</div>

> [@hborla](#):
>
> Implementation-wise, @John_McCall had a neat idea to break the property wrapper into two different types -- one with the instance storage and a "composite" type with the instance and shared storage -- and only piece together the composite type when needed, so most of the time you don't need to pay the cost of that pointer.

Right. The idea is that you write this:

```swift
@propertyWrapper
struct Clamped<Value: Comparable> {
  @shared private var bounds: Range<Value>
  private var value: Value

  init(wrappedValue: Value, @shared _: Range<Value>) {
    // There must be a @shared initializer that's at least as
    // accessible as this which has exactly the same parameters
    // as this initializer's @shared parameters.
    // This body can refer to @shared properties, but not directly
    // to its @shared parameters.
    ...
  }

  @shared init(_ bounds: Range<Value>) {
    // This body must initialize the @shared stored properties
    // and cannot use any non-@shared members.
    self.bounds = bounds
  }

  var wrappedValue: Value {
    get { value }
    set { value = bounds.clamping(newValue) }
  }
}

```

That definition gets rewritten/lowered to something functionally like this:

```swift
extension Clamped {
  struct Shared {
    // @shared instance properties from the original type go here.
    private var bounds: Range<Value>

    // @shared initializers from the original type go here.
    init(_ bounds: Range<Value>) {
      self.bounds = bounds
    }
  }

  struct Instance {
    // Non-@shared instance properties from the original type go here.
    private var value: Value

    // Non-@shared initializers from the original type go here.
    // @shared parameters are removed and replaced with an
    // implicit _shared parameter. References to @shared
    // properties in the body are rewritten to use the implicit
    // _shared parameter.
    init(wrappedValue: Value, _shared: UnsafePointer<Shared>) { ... }

    // No other methods go here.
  }

  struct Composite {
    // Static stored properties from the original type go here.
    // The instance properties are always exactly as follows:
    var _shared: UnsafePointer<Shared>
    var _instance: UnsafeMutablePointer<Instance>

    // Methods from the original type go here. References to
    // shared properties are rewritten to use _shared.
    // References to instance properties are rewritten to use
    // _instance.
    var wrappedValue: Value {
      get { _instance.pointee.value }
      set { _instance.pointee.value = _shared.pointee.bounds.clamping(newValue) }
    }
  }
}

```

Then if you have a use site:

```swift
@Clamped(1..<1024) var count: Int

```

This would get lowered like so:

```swift
static var count$shared = Clamped<Int>.Shared(1..<1024)
var count$instance: Clamped<Int>.Instance
var count: Clamped<Int>.Composite {
  _read {
    yield Clamped.Composite(_shared: &count$shared,
                            _instance: &count$instance)
  }
  _modify {
    var temp = Clamped.Composite(_shared: &count$shared,
                                 _instance: &count$instance)
    yield &temp
  }
}

```

---

_[View the full topic](https://forums.swift.org/t/add-shared-storage-to-property-wrappers/49898)._
