While I like the overall direction of the proposal, I feel pretty strongly that it needs another round of iteration before we should accept it.
In particular, I find the idea of exposing the synthesized storage by shadowing the variable name and prefixing with a $ is problematic. In additional to being too magical and clever, the mental model itself is prone to confusion, and as others have pointed out, there are issues around figuring out the visibility (having another access declaration on the same line would be a syntactic nightmare, I think).
I strongly believe that the synthesized storage should not be made directly available at all, and the programmer should create their own backing if they need to access it. I also believe it is important for the writer of the delegate to have more control of what parts of the delegate get exposed to whom.
There are several other ways to expose the necessary functions in a way which is unambiguous with the property's own methods. I've mentioned a few in the thread, but there are lots of others.
For example:
We could have an annotation (strawman: @delegateFunc) that tells the compiler to expose a particular function/property of a delegate to outside users of the decorated property. Then we could use a post-fix operator (either @ or $) to refer to the exposed parts of the storage
@propertyDelegate
struct MyDelegate {
@delegateFunc func foo() {...}
func bar() {...}
}
struct MyType {
@MyDelegate var zaz:Int
func someFunc () {
self.zaz$.foo() //This can be accessed
self.zaz$.bar() //This can be accessed within the property's type
}
}
myTypeVar.zaz$.foo() //This can still be accessed because of the annotation
myTypeVar.zaz$.bar() //ERROR: this is unavailable outside of the property's type
This lets the delegate control what gets exposed. (Also, if we use @ instead of $, then $ will still be completely free for future use)
The advantage of a post-fix operator, as opposed to a shadow variable (i.e. foo$ instead of $foo) is actually pretty substantial (despite being almost the same syntactically):
- The mental model is easier to understand. I am doing something to the property itself as opposed to referencing a different invisible variable. (e.g.
myProp$.reset()is resetting the property) - When we do get composition, it will naturally compose to allow deeper access (e.g.
myProp$$.deeperFunc())
Tl;dr: We need to spend a little more time thinking through the details of the syntax. One more round. I don't feel like it is fully baked yet...