Problem
In the Property Wrapper proposal, the synthesised variable - in the form: _value
- is deliberately private. There's a problem though, when wanting to use the property as @usableFromInline
. I am aware that this works:
@propertyWrapper
public struct Wrapper<Value> {
public var wrappedValue: Value
@inlinable
public init(wrappedValue: Value) { ... }
}
public struct Foo {
@Wrapper
public var foo: Int
@inlinable
public init(foo: Int) {
self.foo = foo // ✅
}
}
However, when a wrapper has more properties than just wrappedValue
:
@propertyWrapper
public struct Wrapper<Value> {
public var wrappedValue: Value
public var shouldDoSomething: Bool
@inlinable
public init(wrappedValue: Value, shouldDoSomething: Bool) { ... }
}
public struct Foo {
@Wrapper
public var foo: Int
@inlinable
public init(foo: Int) {
self._foo = Wrapper(
wrappedValue: foo,
shouldDoSomething: true
)
// ❌ Property _foo is private, hence, it can't
// be accessed from inlinable initialiser
}
}
Solutions
-
Change behaviour when marking
public
andinternal
wrapped properties @usableFromInline. So that this:@usableFromInline @Wrapper public var foo: Int
Becomes:
@usableFromInline internal var _foo: Wrapper<Int> { ... } public var foo: Int { _foo }
Rather than what I assume would be:
private var _foo: Wrapper<Int> { ... } @usableFromInline // ❌ Can't mark // public property `foo` @usableFromInline public var foo: Int { _foo }
-
Introduce special
@inlinable(underlyingProperty)
attribute, so:public struct Foo { @inlinable(underlyingProperty) @Wrapper public var foo: Int @inlinable public init(foo: Int) { self._foo = Wrapper( wrappedValue: foo, shouldDoSomething: true ) // ✅ } }
-
Other ideas from the community... Do you have any proposals?
My Opinion
I think that the first solution fits better in the direction of the language. It doesn't add further clutter to the language and what it does is mostly expected. When one sees the @usableFromInline
and @Wrapper
'attributes' next to each other, their mind will point them to think that the underlying wrapper property is the one that is 'usedFromInline'.
On the other hand, an intermediate user seeing that a public property is marked @usableFromInline
might be confused, if they're unaware that the proposed feature exists. Furthermore, @usableFromInline(underlyingProperty)
makes it clear that what is '@usableFromInline' applies to the underlying property, not the exposed property foo
.
Relevant
Thanks for readings and letting me know about your thoughts.