While modeling these as effects was neat, I think this revision makes a lot of sense.
It’s perhaps worth some pause that commentators below have immediately started applying this attribute to the property itself rather than the accessor. While not dispositive, I think it might bear some reconsideration whether that apparently more intuitive placement makes sense now that it’s spelled as an attribute.
I agree with the goal of making this a single attribute. In terms of the color of the bikeshed, I think the word “restriction” is a bit counterintuitive from the user perspective. Yes, from a certain vantage point it declares restrictions on what the accessor will access/initialize. However, I think usually one would see it as descriptive rather than prescriptive of what the accessor does; and, moreover, this information increases the expressivity of the language and what users can do.
One additional minor point: to my mind, “accesses” and “initializes,” being descriptions of what the accessor needs and what the accessor does, respectively, feel conceptually like inputs and outputs, which in general we write in that order. For that reason, @storageRestrictions(accesses:initializes:) seems more apt than @storageRestrictions(initializes:accesses:).
It’s possible this was just because the initial revision PR that I linked above inadvertently applied @storageRestrictions at the property level in some instances (corrected here). So, to be clear, the proposed behavior is that this attribute is applied to the init accessor.
Imagining the fully-general version of this feature, we’d definitely want to be able to apply it separately to different accessors since, e.g., the get and set accessors may access different sets of properties. So even if we later allowed applying it at the property level I don’t think the proposed level of granularity would ever go away, and IMO in the interim it would be odd to have the attribute applied in a location that appears to imbue the other accessors with the noted restrictions, when in fact it does no such thing.
I'm in favor of this proposal, but since we are imagining allowing macros to behave like property wrappers , the current proposal does not allow macros to model property wrappers that doesn't have an init(wrappedValue:). In this example from SE-0258, x is of type Bool but the parameter type in the generated member-wise initializer is of type UserDefault<Bool>:
Because init accessor doesn't allow specifying a different parameter type or a different argument label, it's impossible to implement this type of property wrapper using a macro instead:
struct Foo {
var _x: UserDefault<Bool>
var x: Bool {
init(newValue) {
// member-wise initializer argument label will be x ✅
// but newValue is of type Bool ❌
// UserDefault cannot be initialized from a Bool
}
}
var $x: UserDefault<Bool> {
init(newValue) {
// newValue is of type UserDefault<Bool> ✅
// but member-wise initializer argument label will be $x ❌
}
}
}
Therefore, I would like to propose for init accessors to be able to specify a different argument label to be used for the generated member-wise initializer, spelled something like: