# 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:** 1

<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:** [March 21, 2019, 9:30pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/1 "2019-03-21T21:30:09Z")

</div>

Hi all,

**EDIT** : Since I first posted this pitch, the proposal has been significant revised, so I've initiated a new thread with [pitch #2](https://forums.swift.org/t/pitch-2-property-delegates-by-custom-attributes/22855), based on the custom attribute syntax. Please head over there for further comments!

There are property implementation patterns that come up repeatedly. Rather than hardcode a fixed set of patterns into the compiler, we should provide a general "property delegate" mechanism to allow these patterns to be defined as libraries. The complete proposal follows, and the most up-to-date version will be available at:

[https://github.com/DougGregor/swift-evolution/blob/property-delegates/proposals/NNNN-property-delegates.md](https://github.com/DougGregor/swift-evolution/blob/property-delegates/proposals/NNNN-property-delegates.md)

I've made decent progress on [an implementation](https://github.com/apple/swift/pull/23440), but it's not quite to the point where I can build a toolchain for everyone to try out. Comments appreciated!

## Introduction

There are property implementation patterns that come up repeatedly. Rather than hardcode a fixed set of patterns into the compiler, we should provide a general "property delegate" mechanism to allow these patterns to be defined as libraries.

This is an alternative approach to some of the problems intended to be addressed by the [2015-2016 property behaviors proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md). Some of the examples are the same, but this proposal is a completely different approach designed to be simpler, easier to understand for users, and less invasive in the compiler implementation. There is a section that discusses the substantive differences from that design at the end of this proposal.

## Motivation

We've tried to accommodate several important patterns for properties with targeted language support, but this support has been narrow in scope and utility. For instance, Swift provides `lazy` properties as a primitive language feature, since lazy initialization is common and is often necessary to avoid having properties be exposed as `Optional`. Without this language support, it takes a lot of boilerplate to get the same effect:

```swift
struct Foo {
  // lazy var foo = 1738
  private var _foo: Int?
  var foo: Int {
    get {
      if let value = _foo { return value }
      let initialValue = 1738
      _foo = initialValue
      return initialValue
    }
    set {
      _foo = newValue
    }
  }
}

```

Building `lazy` into the language has several disadvantages. It makes the language and compiler more complex and less orthogonal. It's also inflexible; there are many variations on lazy initialization that make sense, but we wouldn't want to hardcode language support for all of them.

There are important property patterns outside of lazy initialization. It often makes sense to have "delayed", once-assignable-then-immutable properties to support multi-phase initialization:

```swift
class Foo {
  let immediatelyInitialized = "foo"
  var _initializedLater: String?

  // We want initializedLater to present like a non-optional 'let' to user code;
  // it can only be assigned once, and can't be accessed before being assigned.
  var initializedLater: String {
    get { return _initializedLater! }
    set {
      assert(_initializedLater == nil)
      _initializedLater = newValue
    }
  }
}

```

Implicitly-unwrapped optionals allow this in a pinch, but give up a lot of safety compared to a non-optional 'let'. Using IUO for multi-phase initialization gives up both immutability and nil-safety.

The attribute `@NSCopying` introduces a use of `NSCopying.copy()` to create a copy on assignment. The implementation pattern may look familiar:

```swift
class Foo {
  // @NSCopying var text: NSAttributedString
  var _text: NSAttributedString
  var text: NSAttributedString {
    get { return _text }
    set { _text = newValue.copy() as! NSAttributedString }
  }
}

```

## Proposed solution

We propose the introduction of **property delegates** , which allow a `var` declaration to state which **delegate** is used to implement it. Borrowing from [Kotlin's delegated properties](https://kotlinlang.org/docs/reference/delegated-properties.html), we propose the `by` keyword to indicate the delegate:

```swift
var foo by Lazy = 1738

```

This implements the property `foo` in a way described by the _property delegate type_ for `Lazy`:

```swift
@propertyDelegate
enum Lazy<Value> {
  case uninitialized(() -> Value)
  case initialized(Value)

  init(initialValue: @autoclosure @escaping () -> Value) {
    self = .uninitialized(initialValue)
  }

  var value: Value {
    mutating get {
      switch self {
      case .uninitialized(let initializer):
        let value = initializer()
        self = .initialized(value)
        return value
      case .initialized(let value):
        return value
      }
    }
    set {
      self = .initialized(newValue)
    }
  }
}

```

A property delegate type provides the storage for a property that names it after `by`. The `value` property provides the actual implementation of the delegate, while the (optional) `init(initialValue:)` enables initialization of the storage from a value of the property's type. The property declaration

```swift
var foo by Lazy = 1738

```

translates to:

```swift
var $foo: Lazy<Int> = Lazy<Int>(initialValue: 1738)
var foo: Int {
  get { return $foo.value }
  set { $foo.value = newValue }
}

```

The use of the prefix `$` for the synthesized storage property name is deliberate: it provides a predictable name for the backing storage, so that delegate types can provide API. For example, we could provide a `reset(_:)` operation on `Lazy` to set it back to a new value:

```swift
extension Lazy {
  /// Reset the state back to "uninitialized" with a new,
  /// possibly-different initial value to be computed on the next access.
  mutating func reset(_ newValue: @autoclosure @escaping () -> Value) {
    self = .uninitialized(newValue)
  }
}

$foo.reset(42)

```

Like other declarations, the synthesized storage property will be `internal` by default, or the access level of the original property if it is less than `internal`. However, it can be given more lenient access by putting the access level after `by`, e.g.,

```swift
// both foo and $foo are publicly visible
public var foo: Int by public Lazy = 1738

```

The property delegate instance can be initialized directly by providing the initializer arguments in parentheses after the name. For example,

```swift
extension Lazy {
  init(closure: @escaping () -> Value) {
    self = .uninitialized(closure)
  }
}

public var foo: Int by Lazy(closure: { 42 })

```

## Examples

Before describing the detailed design, here are some more examples of delegates.

### Delayed Initialization

A property delegate can model "delayed" initialization delegate, where the definite initialization (DI) rules for properties are enforced dynamically rather than at compile time. This can avoid the need for implicitly-unwrapped optionals in multi-phase initialization. We can implement both a mutable variant, which allows for reassignment like a `var`:

```swift
@propertyDelegate
struct DelayedMutable<Value> {
  private var _value: Value? = nil

  var value: Value {
    get {
      guard let value = _value else {
        fatalError("property accessed before being initialized")
      }
      return value
    }
    set {
      _value = newValue
    }
  }

  /// "Reset" the delegate so it can be initialized again.
  mutating func reset() {
    _value = nil
  }
}

```

and an immutable variant, which only allows a single initialization like a `let`:

```swift
@propertyDelegate
struct DelayedImmutable<Value>: Value {
  private var _value: Value? = nil

  var value: Value {
    get {
      guard let value = _value else {
        fatalError("property accessed before being initialized")
      }
      return value
    }

    // Perform an initialization, trapping if the
    // value is already initialized.
    set {
      if _value != nil {
        fatalError("property initialized twice")
      }
      _value = initialValue
    }
  }
}

```

This enables multi-phase initialization, like this:

```swift
class Foo {
  var x: Int by DelayedImmutable

  init() {
    // We don't know "x" yet, and we don't have to set it
  }

  func initializeX(x: Int) {
    self.x = x // Will crash if 'self.x' is already initialized
  }

  func getX() -> Int {
    return x // Will crash if 'self.x' wasn't initialized
  }
}

```

### `NSCopying`

Many Cocoa classes implement value-like objects that require explicit copying. Swift currently provides an `@NSCopying` attribute for properties to give them delegate like Objective-C's `@property(copy)`, invoking the `copy` method on new objects when the property is set. We can turn this into a delegate:

```swift
@propertyDelegate
stuct Copying<Value: NSCopying> {
  private var _value: Value
  
  init(initialValue value: Value) {
    // Copy the value on initialization.
    self._value = value.copy() as! Value
  }

  var value: Value {
    get { return _value }
    set {
      // Copy the value on reassignment.
      _value = newValue().copy() as! Value
    }
  }
}

```

This implementation would address the problem detailed in [SE-0153](https://github.com/apple/swift-evolution/blob/master/proposals/0153-compensate-for-the-inconsistency-of-nscopyings-behaviour.md). Leaving the `copy()` out of `init(initialValue:)` implements the pre-SE-0153 semantics.

### `Unsafe(Mutable)Pointer`

The `Unsafe(Mutable)Pointer` types could be augmented to be property delegate types, allowing one to access the referenced value directly using the `by` syntax. For example:

```swift
@propertyDelegate
struct UnsafeMutablePointer<Pointee> {
  var pointee: Pointee { ... }
  
  var value: Pointee {
    get { return pointee }
    set { pointee = newValue
  }
}

var someInt: Int by UnsafeMutablePointer(mutating: addressOfAnInt)
someInt = 17 // equivalent to someInt.value = 17

```

## Detailed design

### Property delegate types

A _property delegate type_ is a type that can be used as a property delegate. There are three basic requirements for a property delegate type:

1. The property delegate type must be defined with the attribute `@propertyDelegate`. The attribute indicates that the type is meant to be used as a property delegate type, and provides a point at which the compiler can verify the other consistency rules.
2. The property delegate type must be generic, with a single generic type parameter. The type parameter will filled in with the type of the variable that uses the property delegate type.
3. The property delegate type must have a property named `value` whose type is that of the single generic type parameter. This is the property used by the compiler to access the underlying value on the delegate instance.

### Initialization of synthesized storage properties

Introducing a property delegate to a property makes that property computed (with a getter/setter) and introduces a stored property whose type uses the delegate type. That stored property can be initialized in one of two ways:

1. Via a value of the original property's type (e.g., `Int` in `var foo: Int by Lazy`, using the the property delegate type's  
`init(initialValue:)` initializer. That initializer must have a single  
parameter of the property delegate type's generic type parameter (or  
be an `@autoclosure` thereof). When `init(initialValue:)` is present,  
is is always used for the initial value provided on the property  
declaration. For example:

2. Via a value of the property delegate type, by placing the call arguments after the property delegate type:

### Type inference with delegates

Type inference for properties with delegates involves both the type annotation of the original property (if present) and the delegate type, using the initialization of the synthesized stored property. For example:

```swift
var foo by Lazy = 17
// type inference as in...
var $foo: Lazy = Lazy(initialValue: 17)
// infers the type of 'foo' to be 'Int'

```

The same applies when directly initialize the property delegate type, e.g.,

```swift
var someInt by UnsafeMutablePointer(mutating: addressOfInt)
// type inference as in...
var $someInt: UnsafeMutablePointer = UnsafeMutablePointer.init(mutating: addressOfInt)
// infers the type of 'someInt' to be 'Int'

```

### Using delegates in property declarations

A property declaration can specify its delegate following the `by` keyword:

```plaintext
pattern-initializer ::= pattern property-delegate[opt] initializer[opt]

property-delegate ::= 'by' access-level-modifier[opt] type property-delegate-init[opt]

property-delegate-init ::= parenthesized-expression
                       ::= tuple-expression

```

The _type_ in a _property-delegate_ must refer to a property delegate type without specifying a generic argument. The _access-level-modifier_ can be any of `private`, `fileprivate`, `internal`, or `public`, but cannot be less restrictive than the property declaration itself.

### Mutability of properties with delegates

A property with a delegate must be introduced with the `var` keyword. If the `value` property of the behavior type lacks a setter (or the setter is inaccessible), `value` will not have a setter. However, the synthesized storage property could still be mutated.

### Out-of-line initialization of properties with delegates

A property that has a delegate can be initialized after it is defined, either via the property itself (if the delegate type has an `init(initialValue:)`) or via the synthesized storage property. For example:

```swift
let x: Int by Lazy
// ...
x = 17 // okay, treated as $x = .init(initialValue: 17)

```

The synthesized storage property can also be initialized directly, e.g.,

```swift
var y: Int by UnsafeMutable
// ...
$y = UnsafeMutable<Int>(pointer: addressOfInt) // okay

```

Note that the rules of [definite initialization](https://developer.apple.com/swift/blog/?id=28) (DI) apply to properties that have delegates. Let's expand the example of `x` above to include a re-assignment and use `var`:

```swift
var x2: Int by Lazy
// ...
x2 = 17 // okay, treated as $x2 = .init(initialValue: 17)
// ...
x2 = 42 // okay, treated as x2 = 42 (calls the Lazy.value setter)

```

### Memberwise initializers

Structs implicitly declare memberwise initializers based on the stored properties of the struct. With a property that has a delegate, the property is technically computed because it's the synthesized property (of the delegate's type) that is stored. However, the delegate itself might be an implementation detail that should not affect the form of the memberwise initializer.

The parameter type that is introduced into an implicit memberwise initializer for a property with a delegate is determined as follows:

- If the delegate type contains an `init(initialValue:)`, the parameter type is the original type of the property.
- When the delegate type does not contain an `init(initialValue:)`, the parameter type is the type of the synthesized storage property (i.e., a specialization of the delegate type). In this case, the access level of the implicit initializer may need to be adjusted to account for a visibility of the delegate: if the delegate is private (e.g., `var x: Int by private UnsafeMutablePointer`), then the implicit memberwise initializer will be `private`.

For example:

```swift
struct Foo {
  var x: Int by fileprivate UnsafeMutable
  var y: Int by Lazy = 17

  // implicit memberwise initializer:
  fileprivate init(x: UnsafeMutable<Int>, y: Int = 17) {
    self.$x = x
    self.$y = .init(initialValue: y)
  }
}

```

Synthesis for `Encodable`, `Decodable`, `Hashable`, and `Equatable` follows the same rules, using the underlying `value` of the property delegate type contains an `init(initialValue:)` and the synthesized storage property's type otherwise.

### $ identifiers

Currently, identifiers starting with a `$` are not permitted in Swift programs. Today, such identifiers are only used in LLDB, where they can be used to name persistent values within a debugging session.

This proposal loosens these rules slightly: the Swift compiler will introduce identifiers that start with `$` (for the synthesized storage property), and Swift code can reference those properties. However, Swift code cannot declare any new entities with an identifier that begins with `$`. For example:

```swift
var x by Lazy = 17
print($x) // okay to refer to compiler-defined $x
let $y = 17 // error: cannot declare entity with $-prefixed name '$y'

```

### Restrictions on the use of property delegates

There are a number of restrictions on the use of property delegates when defining a property:

- A property with a delegate may not declared inside a protocol.
- An instance property with a delegate may not declared inside an extension.
- An instance property may not be declared in an `enum`.
- A property with a delegate that is declared within a class must be `final` and cannot override another property.
- A property with a delegate may not declare any accessors.
- A property with a delegate cannot be `lazy`, `@NSCopying`, or `@NSManaged`.
- A property with a delegate must be the only property declared within its enclosing declaration (e.g., `var (x, y) by Lazy = /* ... */` is ill-formed)

## Impact on existing code

By itself, this is an additive feature that doesn't impact existing code. However, with some of the property delegates suggested, it can potentially obsolete existing, hardcoded language features. `@NSCopying` could be completely replaced by a `Copying` property delegate type introduced in the `Foundation` module. `lazy` cannot be completely replaced because it's initial value can refer to the `self` of the enclosing type; see 'deferred evaluation of initialization expressions\_. However, it may still make sense to introduce a `Lazy` property delegate type to cover many of the common use cases, leaving the more-magical `lazy` as a backward-compatibility  
feature.

## Alternatives considered

### Using a formal protocol instead of `@propertyDelegate`

Instead of a new attribute, we could introduce a `PropertyDelegate` protocol to describe the semantic constraints on property delegate types. It might look like this:

```swift
protocol PropertyDelegate {
  associatedtype Value
  var value: Value { get }
}

```

There are a few issues here. First, a single protocol `PropertyDelegate` cannot handle all of the variants of `value` that are implied by the section "Mutability of properties with delegates", because we'd need to cope with `mutating get` as well as `set` and `nonmutating set`. Moreover, protocols don't support optional requirements, like `init(initialValue:)` (which also has two forms: one accepting a `Value` and one accepting an `@autoclosure () -> Value`) and `init()`. To cover all of these cases, we would need a several related-but-subtly-different protocols.

The second issue that, even if there were a single `PropertyDelegate` protocol, we don't know of any useful generic algorithms or data structures that seem to be implemented in terms of only `PropertyDelegate`.

## The 2015-2016 property behaviors design

Property delegates address a similar set of use cases to _property behaviors_, which were [proposed and reviewed](https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md) in late 2015/early 2016. The design did not converge, and the proposal was deferred. This proposal picks up the thread, using much of the same motivation and some design ideas, but attempting to simplify the feature and narrow the feature set. Some substantive differences from the prior proposal are:

- Behaviors were introduced into a property with the `[behavior]` syntax, rather than the `by delegate` syntax described here. See the property behaviors proposal for more information.

- Delegates are always expressed by a (generic) type. Property behaviors had a new kind of declaration (introduced by the `behavior` keyword). Having a new kind of declaration allowed for the introduction of specialized syntax, but it also greatly increased the surface area (and implementation cost) of the proposal. Using a generic type makes property delegates more of a syntactic-sugar feature that is easier to implement and explain.

- Delegates cannot declare new kinds of accessors (e.g., the `didChange` example from the property behaviors proposal).

- Delegates used for properties declared within a type cannot refer to the `self` of their enclosing type. This eliminates some use cases (e.g., implementing a `Synchronized` property delegate type that uses a lock defined on the enclosing type), but simplifies the design.

- Delegates can be initialized out-of-line, and one can use the `$`-prefixed name to refer to the storage property. These were future directions in the property behaviors proposal.

---

<div class="post-metadata">

**Author:** ![David\_Smith](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_smith/32/37508_2.png) [@David\_Smith](https://forums.swift.org/u/David_Smith)\
**Post date:** [March 21, 2019, 9:46pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/2 "2019-03-21T21:46:26Z")

</div>

Are nested delegates allowed? e.g. `var userIcon: NSImage by NSCopying by Lazy`

---

<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:** [March 21, 2019, 10:01pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/3 "2019-03-21T22:01:44Z")

</div>

No, multiple composed delegates are not supported. To compose delegates, write a new behavior type that does what you need.

---

<div class="post-metadata">

**Author:** ![rxwei](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/rxwei/32/664_2.png) [@rxwei](https://forums.swift.org/u/rxwei)\
**Post date:** [March 21, 2019, 10:09pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/4 "2019-03-21T22:09:26Z")

</div>

Will property delegate types be added to the standard library?

---

<div class="post-metadata">

**Author:** ![harlanhaskins](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/harlanhaskins/32/333_2.png) [@harlanhaskins](https://forums.swift.org/u/harlanhaskins)\
**Post date:** [March 21, 2019, 10:11pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/5 "2019-03-21T22:11:30Z")

</div>

> [@rxwei](#):
>
> Will property delegate types be added to the standard library?

I'd imagine specific property delegates would get their own Evolution proposals.

---

<div class="post-metadata">

**Author:** ![mackoj](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mackoj/32/42395_2.png) [@mackoj](https://forums.swift.org/u/mackoj)\
**Post date:** [March 21, 2019, 10:18pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/6 "2019-03-21T22:18:23Z")

</div>

Can we build COW containers with it ?  
Should the standard library provide some property delegate ?

---

<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:** [March 21, 2019, 10:23pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/7 "2019-03-21T22:23:30Z")

</div>

> [@harlanhaskins](#):
>
> I'd imagine specific property delegates would get their own Evolution proposals.

I agree that it's probably best to have a separate Evolution proposal for the library side, but let's see what cool property delegate types people come up with!

Doug

---

<div class="post-metadata">

**Author:** ![Aciid](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aciid/32/429_2.png) [@Aciid](https://forums.swift.org/u/Aciid)\
**Post date:** [March 21, 2019, 10:39pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/8 "2019-03-21T22:39:19Z")

</div>

lazy thread-safe 😀

---

<div class="post-metadata">

**Author:** ![ddunbar](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ddunbar/32/1933_2.png) [@ddunbar](https://forums.swift.org/u/ddunbar)\
**Post date:** [March 21, 2019, 10:42pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/9 "2019-03-21T22:42:44Z")

</div>

Is it necessary to restrict the delegate to be a static type, versus something which could be computed by an expression? Alternately, could property delegates be allowed to take parameters?

I don't have a worked example, but this would make them very useful for "registration" scenarios where the property delegate needs some additional context to do its job.

---

<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:** [March 21, 2019, 10:55pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/10 "2019-03-21T22:55:05Z")

</div>

> [@ddunbar](#):
>
> Is it necessary to restrict the delegate to be a static type, versus something which could be computed by an expression? Alternately, could property delegates be allowed to take parameters?

You can call any initializer of the property delegate by putting the initialize arguments in parentheses following the delegate type, e.g.,

```swift
var x: Data by StatefulDelegate(url: URL("http://swift.org"))

```

The `UnsafeMutablePointer` example does this. I (or someone) could probably come up with a more semantic example showing this off. Does this address your concerns?

Doug

---

<div class="post-metadata">

**Author:** ![ddunbar](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ddunbar/32/1933_2.png) [@ddunbar](https://forums.swift.org/u/ddunbar)\
**Post date:** [March 21, 2019, 11:03pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/11 "2019-03-21T23:03:40Z")

</div>

Sorry, I missed that. Yes, that is perfect, and I would be super happy to have access to a feature like this, I can think of several places it would clean up some of the larger Swift code bases we have (mostly around registration).

- Daniel

---

<div class="post-metadata">

**Author:** ![harlanhaskins](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/harlanhaskins/32/333_2.png) [@harlanhaskins](https://forums.swift.org/u/harlanhaskins)\
**Post date:** [March 21, 2019, 11:16pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/12 "2019-03-21T23:16:20Z")

</div>

This could be useful if you want to maintain a registry of global user defaults as well.

```swift
enum GlobalSettings {
  static var isFooFeatureEnabled: Bool by UserDefault(key: "FOO_FEATURE_ENABLED", default: false)
  static var isBarFeatureEnabled: Bool by UserDefault(key: "BAR_FEATURE_ENABLED", default: false)
}

```

---

<div class="post-metadata">

**Author:** ![David\_Smith](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/david_smith/32/37508_2.png) [@David\_Smith](https://forums.swift.org/u/David_Smith)\
**Post date:** [March 21, 2019, 11:22pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/13 "2019-03-21T23:22:32Z")

</div>

[former NSUserDefaults maintainer hat on]

Make sure to implement that with -registerDefaults:, rather than checking at the point of access, though!

[/hat]

---

<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:** [March 21, 2019, 11:27pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/14 "2019-03-21T23:27:02Z")

</div>

> [@mackoj](#):
>
> Can we build COW containers with it ?

Funny you should ask.

```swift
// Declare it like:
// var storage: MyStorageBuffer by CopyOnWrite
//
// When not modifying, access it like:
// storage.index(of: …)
//
// When modifying, access it like:
// $storage.unique.append(…)

protocol Copyable: AnyObject {
  func copy() -> Self
}

@propertyDelegate
struct CopyOnWrite<Value: Copyable> {
  init(initialValue: Value) {
    value = initialValue
  }
  
  private(set) var value: Value
  
  var unique: Value {
    mutating get {
      if !isKnownUniquelyReferenced(&value) {
        value = value.copy()
      }
      return value
    }
    set {
      value = newValue
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![fclout](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/fclout/32/36155_2.png) [@fclout](https://forums.swift.org/u/fclout)\
**Post date:** [March 21, 2019, 11:42pm UTC](https://forums.swift.org/t/pitch-property-delegates/21895/15 "2019-03-21T23:42:51Z")

</div>

Can this only be used on properties, or can free variables have it too? (Would LLDB devs be angry that Swift uses $variables in the global namespace?)

If this is accepted, what does the future look like for superseded features like `@NSCopying` and `lazy`?

I'm shocked that no one's proposed an alternate syntax yet, so I'll pitch my two cents in! If I had to invent syntax for this right now, I'd propose `var(Delegate)`. (Would that be ambiguous with tuples?)

---

<div class="post-metadata">

**Author:** ![MrBeardsley](https://avatars.discourse-cdn.com/v4/letter/m/ccd318/32.png) [@MrBeardsley](https://forums.swift.org/u/MrBeardsley)\
**Post date:** [March 22, 2019, 12:21am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/16 "2019-03-22T00:21:03Z")

</div>

Would property delegates provide a way to support KVO without needing the ObjC runtime?

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [March 22, 2019, 12:39am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/17 "2019-03-22T00:39:45Z")

</div>

A good way to think about property delegates is "they can't do anything a computed property can't do, but they _can_ make it a lot nicer". They're almost literally this:

```swift
// var foo: Int by Lazy = 17
var $foo = Lazy<Int>(17)
var foo: Int {
  get { return $foo.value }
  set { $foo.value = newValue }
}

```

except that the compiler will make it a little more efficient. (Sometimes this part does have semantic effects, but not in a way that drastically changes what is and isn't possible.)

So, "can you use computed properties to implement KVO without needing the ObjC runtime"? The answer is…mostly.

```swift
struct Observable: T {
  // for simplicity I'll just use a callback
  var observers: [(T) -> Void]
  var value: T {
    didSet {
      self.observers.forEach { $0(self.value) }
    }
  }

  init(_ value: T) {
    self.value = value
  }

  mutating func addObserver(_ callback: (T) -> Void) {
    self.observers.append(callback)
  }
}

class Test {
  var _foo = Observable<Int>(17)
  var foo: Int {
    get { return _foo.value }
    set { _foo.value = newValue }
  }
}

```

What's missing is that KVO callbacks include the 'self' object (the one that changed), and property delegates _as specified in this proposal_ have no way of getting at that 'self'. (That would also be useful if you had multiple observable properties and didn't want to have separate arrays for each one.) Perhaps that could change in the future, but it's not part of this proposal.

---

<div class="post-metadata">

**Author:** ![Paul\_Cantrell](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/paul_cantrell/32/16764_2.png) [@Paul\_Cantrell](https://forums.swift.org/u/Paul_Cantrell)\
**Post date:** [March 22, 2019, 12:55am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/18 "2019-03-22T00:55:38Z")

</div>

Love this idea, and I’m excited to see it return! This revised version’s power and simplicity is admirable. The `Lazy<Value>` example is beautiful.

I’d have to sleep on the `by` and `$` syntax, but if they’re not perfect, they feel close.

Though I concede its use cases are few, I’d be sorry to lose this:

> - Delegates used for properties declared within a type cannot refer to the `self` of their enclosing type. This eliminates some use cases (e.g., implementing a `Synchronized` property delegate type that uses a lock defined on the enclosing type), but simplifies the design.

Could delegates take `self` as an explicit argument?

```swift
class C {
    var foo: Synchronized(on: self)
}

```

I’m guessing the answer is “no” because `self` isn’t fully initialized until the property already exists. Is there a future direction for this?

Can a generic type follow `by`?

Given that the proposed syntax doesn’t support nested delegates, would it support writing a generic delegate-wrapping delegate? e.g.

`var foo: Int by NestedDelegate(Copying(), inside: DelayedMutable())`

---

<div class="post-metadata">

**Author:** ![jawbroken](https://avatars.discourse-cdn.com/v4/letter/j/cc9497/32.png) [@jawbroken](https://forums.swift.org/u/jawbroken)\
**Post date:** [March 22, 2019, 12:58am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/19 "2019-03-22T00:58:39Z")

</div>

This looks great, and is a nice simplification of the earlier pitch that still hits the major use cases. My immediate thought is that I don't like the syntax, primarily because it is in the wrong place. The current similar features (e.g. lazy and @NSCopying) must appear before the var keyword, where this appears either at the end or in the middle of the property declaration. This creates inconsistency and limits the ability to clean up the property declaration by moving the delegate part to a different line. To expand an example from this thread:

```swift
var x: Data by StatefulDelegate(url: URL(string: "http://swift.org")!) = 
  try! Data(contentsOf: URL(string: "http://example.org")!)

```

it definitely starts to become confusing when you have property delegates with their own initialisers right in the middle of the property declaration. I'm sure you've considered various ideas here, so what were your thoughts about something like:

```swift
@delegate(StatefulDelegate(url: URL(string: "http://swift.org")!))
var x: Data = try! Data(contentsOf: URL(string: "http://example.org")!)

```

with your choice of spelling in place of `@delegate`? This puts it in a place that is consistent with lazy and @NSCopying, and allows for more flexibility in formatting code because it's no longer stuck in the middle.

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [March 22, 2019, 1:04am UTC](https://forums.swift.org/t/pitch-property-delegates/21895/20 "2019-03-22T01:04:02Z")

</div>

> [@Paul\_Cantrell](#):
>
> Love this idea, and I’m excited to see it return! This revised version’s power and simplicity is admirable. The `Lazy<Value>` example is beautiful.

It should be noted that, compared to today’s builtin `lazy` implementation, and SE-30, the version of Lazy proposed here comes at a storage efficiency cost, since the lazy initializer has to be stored inline for every instance and every lazy property.

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