Pitch: Property Delegates

As a feature name, I feel like "property macros" is too generic---it both overpromises (I should be able to define a macro to do anything with a property) and says too little (well, what can I do with them?). That said, I agree that the #Lazy syntax evokes macro expansion, which fits the way in which property delegates are used. It scales okay to the initialization case:

enum GlobalSettings {
  #UserDefault(key: "FOO_FEATURE_ENABLED", defaultValue: false)
  static var isFooFeatureEnabled: Bool
  #UserDefault(key: "BAR_FEATURE_ENABLED", defaultValue: false)
  static var isBarFeatureEnabled: Bool
}

Others have suggested using attribute syntax (e.g., @Lazy) or embracing the $ also for the declaration side ($Lazy); I prefer it to those options because we've already set aside # for things in this space. That said, it makes placing any modifiers (like public to making the storage property visible) a bit awkward---if they go in the parentheses, they look like initialization arguments, but there's no other natural space for them.

We already have "multiple access control modifiers" via private(set), so the notion is not newly-introduced here. Moreover, we are declaring two entities---that's fundamentally how we describe this feature---and it is reasonable that authors could choose whether the delegate is part of their API or not.

Presumably, this means that #Forward is another new feature, but it's using the same syntax as a property delegate. We'll need to be careful in this syntactic space. Also, I think the relationship expressed above is backwards: we want to define fooStorage as a normal (stored?) property, and sugar the declaration of foo that delegates to fooStorage.

Syntax aside, I think your meta-point is reasonable: rather than trying to pack configurability of the storage property into the original property declaration, we could say that there is a syntax for "delegate to this other named property". With the by syntax, this can fall out as a result of name lookup referring to a property:

public var fooStorage: UserDefaults<Int> = ...
public var foo: Int by fooStorage   // okay, we found a property; delegate to that

With a # syntax, we'd probably need something special, e.g.,

public var fooStorage: UserDefaults<Int> = ...
#delegate(to: fooStorage) public var foo: Int

Yes, we could have some kind of #storage(of:). to access the backing storage. I find that to be rather verbose for the use case, but perhaps I haven't sold the use cases well enough to motivate using $. I'll see if I can do better in a revision of the proposal.

Doug