So far, we'd probably already agree that in this area, we (eventually) want
- Supports for multiple kinds of passing
- Out-of-the-box (no additional functions required) pass-by-storage
- Minimal surprises for Unapplied Function Reference (UFR)
- Similarity between function declaration and closure declaration
I believe there are a few possible alterations that could put us in a relatively comfortable spot.
Remove UFR and add fix-it.
It's unlikely we'll have any serious problems. However, unannotated passings for closure and function are still of a different kind (pass-by-storage vs -wrapped). I already discussed it at length, so I won't go further.
Removed automatic init(wrappedValue:)
and allow every wrapper to use the feature.
I think this is the best one I could come up with. It put us in line of everything is pass-by-storage so there is a little-to-no surprise. It would also allow for some interesting expansion into init(wrappedValue:)
later on (see PS below).
If we need to add pass-by-wrapped urgently, we could
Add argument prefix $
to the function call.
So you'd need to do foo($a: a)
instead of just foo(a: a)
. This should add enough room for expansion should we add pass-by-storage to functions and pass-by-wrapped to closure later. At the very least, it allows for { (@Wrapper $a) }
and foo(a: a)
. Though we then have to commit to using the $
prefix to signify pass-by-wrapped, which may not be what we want.
PS
When playing around with the idea of explicit annotation, I think that it's best to be at the argument label. There's a lot of "intuitive" extensions there.
Say normal functions accept both pass-by-storage and pass-by-wrapped:
// Pass-by-storage or pass-by-wrapped
func foo(@Wrapper a: Int) { ... }
You could pass-by-storage or -wrapped using the argument label annotation (I'll use prefix $
, but it should be viable with any kind of call-site annotation)
foo(a: wrapper) // pass-by-storage
foo($a: 0) // pass-by-wrapped
now here's an interesting part, you can force the function to accept only pass-by-wrapped by embedding the annotation into the declaration
func bar(@Wrapper $a: Int) { ... } // Only pass-by-wrapped allowed
You can even distinguish between UFR with pass-by-storage and pass-by-wrapped:
let a = foo(a:) // (Wrapper) -> () pass-by-storage
let b = foo($a:) // (Int) -> () pass-by-wrapped
let c = foo // same as foo(a:)