Hello @amritpan,
I had missed this proposal early on. I know I've certainly come across places where the let
restriction on property wrappers is annoying, and I think it's reasonable to consider lifting the restriction.
I have two concerns with this proposal at this point, one philosophical and one procedural.
The philosophical concern is that a let
constant is immutable. It can't be reassigned, yes, but if the type of the let
constant is of a value type then that value cannot be changed no matter what. Applying a property wrapper to that feels like it weakens the immutability guarantee, because of the ability to introduce a backing reference type. Your WrapperClass
property wrapper, for example, lets us write
_value.wrappedValue = 17
after the let
has been initialized, because _value
has reference semantics. It's possible that the benefit from allowing property wrappers on let
's outweighs the downsides of potential mutability surprises, but we should be cognizant of the guarantees we're losing.
The procedural concern I have is that there are two other proposals in the Swift 5.9 time frame, one accepted and one under review now, that interact with this proposal:
-
SE-0389 "Attached macros" adds "accessor macros", which also can't be applied to
let
declarations. - SE-0400 "Init accessors", under review now, adds the ability to specify the initialization behavior of a property independent of its setter.
One of the stated goals of the second proposal is to get closer to the point where macros can subsume the uses of property wrappers. That goal wasn't really understood at the time you pitched your proposal, because macros (and especially accessor macros) were really just starting to come into focus then. However, your proposal would take a step away from that goal if property wrappers could be used with let
but accessor macros could not. Therefore, please consider broadening your proposal to encompass accessor macros as well, or if it doesn't work, add an Alternatives Considered section that details why it doesn't work.
I had one last thought... the init accessors proposal (SE-0400) under review allows us expression let
-like single initialization behaviors for computed properties:
var onlySetOnce: Int {
init { /* set it */ }
get { /* get it */ }
// no setter!
}
... which is very similar to how your proposal lets you run code on initialization, and run code when getting a value, without allowing one to directly mutate the property.
Doug