# Pitch: Property Delegates

**URL:** <https://forums.swift.org/t/pitch-property-delegates/21895>\
**Category:** Pitches\
**Created:** [March 21, 2019, 9:30pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895 "2019-03-21T21:30:09Z")\
**Posts on this page:** 18\
**Page:** 14

<div class="post-metadata">

**Author:** ![ethanjdiamond](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ethanjdiamond/32/2353_2.png) [@ethanjdiamond](https://forums.swift.org/u/ethanjdiamond)\
**Post date:** [April 3, 2019, 3:59am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/265 "2019-04-03T03:59:26Z")

</div>

> [@hartbit](#):
>
> I'd like to second this. It seems like many people (me too) want their storage properties to be `private/fileprivate` . In that case, not only do we need an easy way to achieve that, but if it's the most predominant access level for property delegate storage, that's a strong argument for making it the default.

I'm still unclear on what the use case is for internal/public storage properties. Does someone have an example of when that might be useful?

---

<div class="post-metadata">

**Author:** ![Jon\_Hull](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jon_hull/32/678_2.png) [@Jon\_Hull](https://forums.swift.org/u/Jon_Hull)\
**Post date:** [April 3, 2019, 9:06am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/266 "2019-04-03T09:06:27Z")

</div>

Regarding the discussion of $foo and what it's access level should be, why give access to the backing store at all unless the programmer creates it? Then the whole thing simplifies and the argument becomes moot...

Instead of

```swift
private var $foo:Delegate //Compiler automatically creates this as storage whether I need it or not
public var foo by private Delegate = 10

```

just:

```swift
//compiler creates a storage variable without a programmer accessible name
public var foo by Delegate = 10

```

If you need access to the backing store for some reason then you create it yourself:

```swift
private var myStorage = Delegate(10) //This is just a normal var and I can give it whatever access level I want
public var foo by myStorage

```

To me, this feels a lot more predictable and less magical... and we aren't burning $

---

<div class="post-metadata">

**Author:** ![dwaite](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dwaite/32/1200_2.png) [@dwaite](https://forums.swift.org/u/dwaite)\
**Post date:** [April 3, 2019, 4:35pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/267 "2019-04-03T16:35:37Z")

</div>

I rather prefer this being aligned with macro syntax; I believe if/when user-defined macros become a swift feature, this property delegates feature becomes a legacy version of that more powerful feature.

In that alternate future, @propertyDelegate (however it is spelled) would be an attribute telling the compiler to convert that type into a property-viable macro.

---

<div class="post-metadata">

**Author:** ![Jean-Daniel](https://avatars.discourse-cdn.com/v4/letter/j/977dab/32.png) [@Jean-Daniel](https://forums.swift.org/u/Jean-Daniel)\
**Post date:** [April 3, 2019, 8:23pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/268 "2019-04-03T20:23:02Z")

</div>

> [@ethanjdiamond](#):
>
> I'm still unclear on what the use case is for internal/public storage properties. Does someone have an example of when that might be useful?

Writing Observable properties without the need to write a addObserver/removeObserver wrapper for each one (as the storage will already expose these methods).

---

<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:** [April 3, 2019, 9:58pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/269 "2019-04-03T21:58:20Z")

</div>

Another example would be `@Atomic`, assuming we can find a way to make atomic types sound as a general matter. It's certainly useful to be able to simply load and store the underlying value, but the `Atomic` delegate type would also provide operations like `exchange` and `compareAndExchange`, as well as loads and stores with explicit memory-ordering semantics. While it's generally good practice to encapsulate atomic properties, that includes the abstract storage and not just the backing storage.

---

<div class="post-metadata">

**Author:** ![nnnnnnnn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nnnnnnnn/32/264_2.png) [@nnnnnnnn](https://forums.swift.org/u/nnnnnnnn)\
**Post date:** [April 3, 2019, 11:44pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/270 "2019-04-03T23:44:22Z")

</div>

Would it be problematic to allow an optional access control keyword at the beginning of the parenthesized arguments?

```swift
@Lazy(private) 
public var x = 10

@UserDefault(fileprivate, key: "FOO_FEATURE_ENABLED", defaultValue: false)
static var isFooFeatureEnabled: Bool

```

If omitted the delegate would default to the minimum of `internal` or the property's declaration. That looks broadly consistent with our sort of weird hand-wavy attribute syntax practices — e.g. `@available(swift, introduced: 5)`.

---

<div class="post-metadata">

**Author:** ![anandabits](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/anandabits/32/355_2.png) [@anandabits](https://forums.swift.org/u/anandabits)\
**Post date:** [April 3, 2019, 11:49pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/271 "2019-04-03T23:49:19Z")

</div>

> [@nnnnnnnn](#):
>
> Would it be problematic to allow an optional access control keyword at the beginning of the parenthesized arguments?

This breaks the symmetry with normal initializer calls. If we’re going to support explicit access control I think `private(storage)` is the way to do it. Are there good arguments against that syntax?

---

<div class="post-metadata">

**Author:** ![nnnnnnnn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nnnnnnnn/32/264_2.png) [@nnnnnnnn](https://forums.swift.org/u/nnnnnnnn)\
**Post date:** [April 3, 2019, 11:52pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/272 "2019-04-03T23:52:07Z")

</div>

Ah, akin to `private(set)`. So those would be:

```swift
@Lazy
public private(storage) var x = 10

@UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false)
fileprivate(storage) static var isFooFeatureEnabled: Bool

```

That looks good to me, as well.

---

<div class="post-metadata">

**Author:** ![davedelong](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/davedelong/32/38708_2.png) [@davedelong](https://forums.swift.org/u/davedelong)\
**Post date:** [April 4, 2019, 12:25am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/273 "2019-04-04T00:25:08Z")

</div>

> [@nnnnnnnn](#):
>
> ```
> @UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false) 
> fileprivate(storage) static var isFooFeatureEnabled: Bool
> 
> ```

How would something like a `UserDefault` property delegate handle dynamically-named keys? All the examples thus far have been using static keys. But, for example, in a document-based app you'd want to name-space keys with a document identifier, which cannot be known at compile time and will change for every document.

---

<div class="post-metadata">

**Author:** ![beccadax](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/beccadax/32/34217_2.png) [@beccadax](https://forums.swift.org/u/beccadax)\
**Post date:** [April 4, 2019, 12:33am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/274 "2019-04-04T00:33:47Z")

</div>

> [@davedelong](#):
>
> How would something like a `UserDefault` property delegate handle dynamically-named keys?

If the document identifier is known at initialization time, and assuming this should be an instance property instead of a type property (which seems right for a per-document thing), you could do something like this:

```swift
@UserDefault
fileprivate(storage) var isFooFeatureEnabled: Bool

init(documentID: UUID, ...) {
  $isFooFeatureEnabled = UserDefault(key: "\(documentID).FOO_FEATURE_ENABLED", defaultValue: false)
  ...
}

```

Future improvements might make this more elegant, e.g.:

```swift
var documentID: UUID

@UserDefault(key: { "\($0.documentID).FOO_FEATURE_ENABLED" }, defaultValue: false)
fileprivate(storage) var isFooFeatureEnabled: Bool

```

---

<div class="post-metadata">

**Author:** ![michelf](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/michelf/32/1180_2.png) [@michelf](https://forums.swift.org/u/michelf)\
**Post date:** [April 4, 2019, 1:08am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/275 "2019-04-04T01:08:45Z")

</div>

Has it come to the attention of anyone that these implementations of `Lazy` and `UserDefaults` waste memory? Flatten them a bit and you get this for `Lazy`:

```swift
class C {
    var somethingToCheck: Bool { ... generated accessors ... }
    var $somethingToCheck = Lazy<Bool>(initialValue: { ... some closure ... })
}

```

Notice how `Lazy` ends up storing its closure within the class instance. The _same closure_ will be stored in _each instance_ of the class. Wouldn't it make more sense for the closure to be stored only once as a static variable? You'd probably end up saving 15 to 16 bytes in the case above.

Same can be said about `UserDefaults`:

```swift
class C {
    var someSetting: Bool { ... generated accessors ... }
    var $someSetting = UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false)
}

```

Here again `UserDefault` ends up storing the same `key` and same `defaultValue` within each class instance.

Should we assume the compiler will notice what's going on and manage to optimize all this away? That seems unlikely to me, and I don't find this very appealing.

---

<div class="post-metadata">

**Author:** ![andyj-at-aspin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/andyj-at-aspin/32/18552_2.png) [@andyj-at-aspin](https://forums.swift.org/u/andyj-at-aspin)\
**Post date:** [April 5, 2019, 3:30pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/276 "2019-04-05T15:30:51Z")

</div>

I wish!

---

<div class="post-metadata">

**Author:** ![Karl](https://avatars.discourse-cdn.com/v4/letter/k/34f0e0/32.png) [@Karl](https://forums.swift.org/u/Karl)\
**Post date:** [April 6, 2019, 7:05am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/277 "2019-04-06T07:05:23Z")

</div>

So as I understand it, this is essentially a [Python descriptor](https://docs.python.org/2/howto/descriptor.html), which can also be used like a decorator as long as the function doesn't take any arguments.

If property delegates were marked using a protocol, we could decouple the generic parameter from the property's type, which would allow us to return a wrapper function:

```swift
protocol PropertyDelegate {
  associatedtype PropertyType
  var value: PropertyType { get }
}
// Not shown: MutablePropertyDelegate

struct Profiled<T> {
  var runtimes = [TimeInterval]()
  let decorated: () -> T

  init(_ fn: () -> T) {
    self.decorated = { 
      let start = NSDate()
      let result = fn()
      runtimes.append(NSDate().timeIntervalSince(start))
      return result
    }
  }
}

extension Profiled: PropertyDelegate {
  typealias PropertyType = ()->T
  var value: ()->T { return decorated }
}

struct Something {
  @Profiled { 
   // Lots of code, long-running function.
   // ...
  }
  var myFunction
}

let thing = Something()
thing.myFunction()
thing.myFunction()
thing.myFunction()
print(thing.$myFunction.runtimes)

```

I'm not sure if this is the most current proposed syntax, so perhaps I'm repeating things others have said, but this syntax doesn't look _amazing_.

With reference to the point about feature-creep: of course we cannot consider arbitrary future features, but this is a significant one (especially for server frameworks and scripting) that would likely see _far_ more usage than lazy/NSCopying. Hopefully it is reasonably focussed: the mental model is essentially the same - just as a "property delegate" wraps some underlying property storage, a decorator wraps an underlying function.

Once the proposal is updated I'll be able to say more. Right now it's difficult to find the "latest version".

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [April 9, 2019, 6:44am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/279 "2019-04-09T06:44:08Z")

</div>

> [@Douglas\_Gregor](#):
>
> > Relaxation of the single generic type parameter requirement.
> > 
> > Is it possible to relax this rule in a `init(initialValue:)` fashion? Here I mean to make the single generic type parameter optional but required for certain syntax forms.
> 
> It is possible, yes, but it makes the model more complex, and all of the examples given so far have been theoretical or contrived. I don't feel that the complexity is warranted at this stage.

I've been thinking about this more, and my argument against your generalization was really poor. I think it's important that we allow for the inference in the common case (`@Lazy var x: Int` rather than `@Lazy<Int> var x: Int`), but if the user is going to specify the full type of the property delegate type, it's completely reasonable to get the original property's type from the `value` of that type.

Sorry for not seeing this earlier. My [newer implementation](https://github.com/apple/swift/pull/23701) handles things this way, and the upcoming revision of the proposal drops the restrictions.

Thank you,  
Doug

---

<div class="post-metadata">

**Author:** ![DevAndArtist](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/devandartist/32/287_2.png) [@DevAndArtist](https://forums.swift.org/u/DevAndArtist)\
**Post date:** [April 9, 2019, 11:29am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/280 "2019-04-09T11:29:12Z")

</div>

Ah it was a reply to the reply to my reply :D Discourse wasn't able to notify me.

That relaxation makes the requirement of the single generic type parameter completely optional, so you can have 0 to n generic type parameters. So it's best that the types are always matched against `value` which is strengthened by the access level rules as `value` has the same access level as the property delegate type. In most common cases you'll be able to omit the generic type parameter list, which is what you initially wanted, but in other cases the user will be able to create more powerful/flexible property delegates.

---

<div class="post-metadata">

**Author:** ![AlexanderM](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/alexanderm/32/9781_2.png) [@AlexanderM](https://forums.swift.org/u/AlexanderM)\
**Post date:** [April 19, 2019, 5:26am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/281 "2019-04-19T05:26:29Z")

</div>

For an IBOutlet of type `MyView`, it would:

1. Hide the optionality of `MyView` (which is currently necessary, because these properties are set by the story board as a second step, after object initialization.
2. Error out when accessed before set.
3. Error out when set a second time.

See this comment for an example: [Pitch: Property Delegates - #34 by DevAndArtist](https://forums.swift.org/t/pitch-property-delegates/21895/34)

---

<div class="post-metadata">

**Author:** ![MarinaHuber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/marinahuber/32/12641_2.png) [@MarinaHuber](https://forums.swift.org/u/MarinaHuber)\
**Post date:** [December 24, 2019, 10:27pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/282 "2019-12-24T22:27:34Z")

</div>

Sorry for late post....Has this been accepted?

---

<div class="post-metadata">

**Author:** ![Jean-Daniel](https://avatars.discourse-cdn.com/v4/letter/j/977dab/32.png) [@Jean-Daniel](https://forums.swift.org/u/Jean-Daniel)\
**Post date:** [December 24, 2019, 11:38pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/283 "2019-12-24T23:38:20Z")

</div>

Search for "property wrappers" which is the accepted feature that result from a lot of changes and discussion since this first attempt.

[Previous page](https://forums.swift.org/t/pitch-property-delegates/21895.md?page=13)
