# 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:** 20\
**Page:** 13

<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 2, 2019, 4:05am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/245 "2019-04-02T04:05:08Z")

</div>

> [@Avi](#):
>
> > `max(internal, access-of-original-property)`
> 
> I don't understand the sort order being used. Is `public` greater or less than `internal` ?

Sorry, it would have been more obvious as `min`: we want the more restrictive of the two.

Doug

---

<div class="post-metadata">

**Author:** ![Avi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/avi/32/2962_2.png) [@Avi](https://forums.swift.org/u/Avi)\
**Post date:** [April 2, 2019, 4:08am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/246 "2019-04-02T04:08:32Z")

</div>

I thought that was the intent, but it didn't match my mental model of "more access is greater-than". Thanks for the clarification.

---

<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 2, 2019, 12:55pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/247 "2019-04-02T12:55:40Z")

</div>

> [@Douglas\_Gregor](#):
>
> I don't think it's important to expose the backing storage property publicly. We can simplify the proposal by not allowing one to specify the access of the backing storage; `max(internal, access-of-original-property)` is reasonable behavior.

It’s not important to expose it publicly but I think much of the time I would want it to be `private` or `fileprivate` while the original property has higher visibility. It is undesirable (to me) to have to expose the storage everywhere in a module for `public` and `internal` properties. We shouldn’t have to choose between syntactic sugar and encapsulation.

---

<div class="post-metadata">

**Author:** ![karim](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/karim/32/1412_2.png) [@karim](https://forums.swift.org/u/karim)\
**Post date:** [April 2, 2019, 1:45pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/248 "2019-04-02T13:45:15Z")

</div>

I think the most reasonable default, especially if there’s no affordance to specify it would be private. If one wants to expose the storage, one can always write a more visible get/set wrapper.

---

<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 2, 2019, 1:53pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/249 "2019-04-02T13:53:33Z")

</div>

> [@karim](#):
>
> I think the most reasonable default, especially if there’s no affordance to specify it would be private. If one wants to expose the storage, one can always write a more visible get/set wrapper.

I tend to agree, although at that point you've nearly abandoned all of the gains of using the syntactic sugar. The plus side of this approach is that you can choose what part of the delegate's API you wish to forward, such as adding an observer.

---

<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 2, 2019, 2:15pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/250 "2019-04-02T14:15:35Z")

</div>

I think here we would want property forwarding to kick in to gain parts of the delegation back. Then you can expose the storage and still delegate to it.

---

<div class="post-metadata">

**Author:** ![djbe](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/djbe/32/3746_2.png) [@djbe](https://forums.swift.org/u/djbe)\
**Post date:** [April 2, 2019, 2:29pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/251 "2019-04-02T14:29:13Z")

</div>

I think @davedelong's comment is spot on, and whatever proposal that would implement this, should also consider the bigger picture

If this proposal goes through and some proxy mechanism later, they should be similar in how they work and work well together. Swift shouldn't become a language with a bunch of different things stapled on, it should be consistent and well thought-out.

For this proposal, it might be worth it taking a step back, and consider what we want to achieve long term.

---

<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 2, 2019, 3:59pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/252 "2019-04-02T15:59:13Z")

</div>

> [@Douglas\_Gregor](#):
>
> The attribute-based pitch (which I'm sorry I haven't been able to write up fully yet) still allows one to explicitly initialize the backing property, e.g.,
> 
> ```swift
> self.$foo = DelegateType(arg: 17)
> 
> ```
> 
> Doug

Thanks for your work on this, Doug. I can already think of several use cases for this in my code base - dependency injection, exposing an RxSubject as an Observable externally, etc. My only concern is that now that we're talking about using the "@" syntax (to which I am +1), does it make sense to burn the $ prefix on storage, particularly since it doesn't show up anywhere else in the feature anymore?

A couple other possibilities, off the cuff:

```swift
self.$foo = DelegateType(arg: 17) // Currently proposed

self._foo = DelegateType(arg: 17) // Auto-generated, _ has precedence for internal
self.@foo = DelegateType(arg: 17) // Auto-generated, matches the @ in the declaration
self.foo.storage = DelegateType(arg: 17) // Doubt there's a way to make this actually work

```

---

<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 2, 2019, 4:20pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/253 "2019-04-02T16:20:42Z")

</div>

I think consistency with the language’s `internal` default for everything else is important here. Remember, Swift is a language where a single type’s definition may be scattered across many files; since stored properties must be declared only in the type’s declaration, `private`-by-default means any logic requiring access to the backing storage would have to be in that one file.

Imagine what this would mean, for example, for the `CopyOnWrite` delegate I described upthread. In that example, the main property was immutable and you had to mutate the value through a property on the backing storage. If the backing storage was private, this would mean you'd have to pile all of the mutation code into the same file as the type's main declaration. Imagine what that would mean for the standard library or another large library which organizes the code in large types into several files (Array.swift, ArrayBody.swift, ArrayBuffer.swift, ...). Will they rip apart their useful per-concern organization to use `@CopyOnWrite`? Will they rewrap the backing storage property in an ad-hoc fashion and depend on the optimizer to remove the overhead? Or will they not use the delegate at all?

(I also think that the lack of separate access control is a bigger flaw than most of us think—the fact that the backing storages disappear when a type is moved into a module will chafe in practice. Not enough that I think it should be made public, but enough that I think it would be a very good idea to _allow_ it to be made public.)

---

<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 2, 2019, 4:56pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/254 "2019-04-02T16:56:59Z")

</div>

> [@djbe](#):
>
> I think @davedelong's comment is spot on, and whatever proposal that would implement this, should also consider the bigger picture
> 
> If this proposal goes through and some proxy mechanism later, they should be similar in how they work and work well together. Swift shouldn't become a language with a bunch of different things stapled on, it should be consistent and well thought-out.
> 
> For this proposal, it might be worth it taking a step back, and consider what we want to achieve long term.

I disagree, and I'm going to disagree more strongly than is strictly necessary because I think this general pattern of discourse can be harmful to the process, particularly for less-experienced proposers.

The pattern looks like this:

1. This proposal looks like a form of 
2. Something like could be useful elsewhere in Swift
3. You should go design all of because your proposal might end up different after that exercise

Abstractly, it's a reasonable line of argument: we _want_ to find the generalization that ties together different ideas, rather than having disparate features that don't compose.

However, when making this "step back and consider the larger picture" argument, it is important to show that there is a plausible larger picture, and what it might look like. That's completely missing here: the entire argument rests on the idea that there is some "proxy pattern" that would subsume property delegates and a bunch of other use cases.

- Those use cases aren't spelled out.
- A more-general feature that covers those use cases isn't spelled out.
- The way in which that more-general feature serves the use cases of the proposal under discussion isn't spelled out.

In fact, there is literally nothing in the post that ties together the feature proposed (property delegates) and the proposed larger picture (proxies) beyond the use of the term "proxy pattern." The suggestion is meant in good faith, but its effect is very different: it's signing the proposal author up for some unspecified amount of work with unclear goals. For a less-assured proposal author, it acts as a roadblock: it's hard to say "no" to a goal that is abstractly good, but impossible to address the comment in a constructive way without exaggerating the scope of the proposal beyond what the author intended (or even cares about).

Contrast this with the suggestion to tie this in with [custom attributes](https://forums.swift.org/t/pitch-introduce-custom-attributes/21335). There, there is a clear link ("re-use the syntax from this other pitch instead of inventing new syntax"), a clear "larger picture" (a pitch for the generalization we're talking about), and clear goals ("we only need the attribute syntax and nothing else new"). We've been having a useful discussion about the technical trade-offs ever since, because the suggestion was concrete enough that we can discuss specific details.

Doug

---

<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 2, 2019, 5:10pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/255 "2019-04-02T17:10:03Z")

</div>

> [@beccadax](#):
>
> I think consistency with the language’s `internal` default for everything else is important here. Remember, Swift is a language where a single type’s definition may be scattered across many files; since stored properties must be declared only in the type’s declaration, `private` -by-default means any logic requiring access to the backing storage would have to be in that one file.

Yeah, another point in favor of `internal`: the implicit member wise initializer is `internal` by default, and delegate types can make their way into the memberwise initializer (when there's no `init(initialValue:)`).

Doug

---

<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 2, 2019, 6:00pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/256 "2019-04-02T18:00:54Z")

</div>

> [@beccadax](#):
>
> Imagine what this would mean, for example, for the `CopyOnWrite` delegate I described upthread. In that example, the main property was immutable and you had to mutate the value through a property on the backing storage. If the backing storage was private, this would mean you'd have to pile all of the mutation code into the same file as the type's main declaration.

It would not mean this - you can still write forwarding APIs that expose the backing storage in whatever way you wish. However, if we don’t have any way to lower the access level then `internal` properties with delegates are **forced** to expose the backing storage. There is no alternative.

> [@beccadax](#):
>
> (I also think that the lack of separate access control is a bigger flaw than most of us think—the fact that the backing storages disappear when a type is moved into a module will chafe in practice. Not enough that I think it should be made public, but enough that I think it would be a very good idea to _allow_ it to be made public.)

Further, if we do have a way to specify access level then the consistent default of `internal` in the above case is acceptable. I don’t mind having to write something like `private(storage)`.

---

<div class="post-metadata">

**Author:** ![hartbit](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hartbit/32/738_2.png) [@hartbit](https://forums.swift.org/u/hartbit)\
**Post date:** [April 2, 2019, 6:44pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/257 "2019-04-02T18:44:49Z")

</div>

> [@anandabits](#):
>
> It would not mean this - you can still write forwarding APIs that expose the backing storage in whatever way you wish. However, if we don’t have any way to lower the access level then `internal` properties with delegates are **forced** to expose the backing storage. There is no alternative.

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.

---

<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 2, 2019, 8:32pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/258 "2019-04-02T20:32:36Z")

</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 find the default to `min(internal, property access)` is a very good tradeoff. I don't mind having my storage exposed for internal properties, but I would find that far more annoying for private and file private properties.

---

<div class="post-metadata">

**Author:** ![mayoff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mayoff/32/613_2.png) [@mayoff](https://forums.swift.org/u/mayoff)\
**Post date:** [April 2, 2019, 9:44pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/259 "2019-04-02T21:44:55Z")

</div>

> [@Douglas\_Gregor](#):
>
> ```swift
> self.$foo = DelegateType(arg: 17)
> 
> ```

Why is `$foo` a better name than `_foo` for the storage of `foo`?

---

<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 2, 2019, 10:59pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/260 "2019-04-02T22:59:43Z")

</div>

> [@anandabits](#):
>
> However, if we don’t have any way to lower the access level then `internal` properties with delegates are **forced** to expose the backing storage.

As long as they don't leak into ABI, I don't think this is the end of the world. Below `internal`, making something too accessible makes certain mistakes slightly harder (but still very tractable!) to catch, while making it not accessible enough means you need to restructure your code to work around the access control system. I think the second is worse than the first.

---

<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 2, 2019, 11:36pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/261 "2019-04-02T23:36:53Z")

</div>

> [@beccadax](#):
>
> while making it not accessible enough means you need to restructure your code to work around the access control system.

I don't think it's fair to call having to write a forwarding API a need to "restructure" your code. It's more verbose than `private(storage)` but it's not a _structural_ change. On the other hand, it's less verbose than manually implementing the backing storage and forwarding the primary property which is the workaround for lack of ability to have lower access to the storage. Do we really want to introduce sugar that is useless when you want `private` storage? I hope not.

---

<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 2, 2019, 11:51pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/262 "2019-04-02T23:51:21Z")

</div>

It would be good if you could set access, but I think the feature can ship without it as a first pass, whereas it would be very limiting if the access was locked to `private`.

---

<div class="post-metadata">

**Author:** ![kiel](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/kiel/32/1392_2.png) [@kiel](https://forums.swift.org/u/kiel)\
**Post date:** [April 2, 2019, 11:54pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/263 "2019-04-02T23:54:06Z")

</div>

I can't think of any problems with this, but is there a problem with the storage being accessible via mirroring or runtime reflection?

---

<div class="post-metadata">

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

</div>

As someone who builds both libraries and apps on a team of developers of mixed skill-levels, I can say that the inability to make storage private while taking advantage of this feature would basically kill its use on our team. We work very hard to achieve real encapsulation in our code because the alternative is endless spaghetti. Exposing storage by default with no way to restrict it would basically make for continuous code-review comments, so the sugar would go entirely unused even when it’s the right tool for the job. This would be hugely unfortunate.

Especially since it would be trivial to expose the private storage via a simple get/set computed property in the case where you wanted it more accessible.

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

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