-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Closed
Labels
bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.A deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfThe Swift compiler itselfproperty wrappersFeature: property wrappersFeature: property wrappers
Description
| Previous ID | SR-11255 |
| Radar | None |
| Original Reporter | luiz (JIRA User) |
| Type | Bug |
| Status | Closed |
| Resolution | Done |
Environment
Apple Swift version 5.1 (swiftlang-1100.0.266.1 clang-1100.0.32.1)
Target: x86_64-apple-darwin19.0.0
macOS Catalina 10.15 Beta (19A526h)
Additional Detail from JIRA
| Votes | 0 |
| Component/s | Compiler |
| Labels | Bug, PropertyWrappers |
| Assignee | @theblixguy |
| Priority | Medium |
md5: a8b0cafcd9338e5a48ba93f8a7954ca9
Issue Description:
In the following code where a property wrapper implements a '_modify' accessor, I expect the 'get' accessor to not be invoked at all when mutating MyWrapper as a property wrapper, just like it doesn't when mutating MyWrapper as an ordinary type, but modifying 'self.wrapper' or 'self.$wrapper' result in a 'get' access followed by a '_modify' access, resulting in potentially duplicated work; note that a modifying access to 'self._wrapper.wrappedValue' does not result in a spurious 'get' access.
@propertyWrapper
public final class MyWrapper<T> {
@usableFromInline
var getterInvokeCount = 0
@usableFromInline
var modifyInvokeCount = 0
@usableFromInline
var _value: T
@inlinable
public var wrappedValue: T {
get {
getterInvokeCount += 1
return _value
}
_modify {
modifyInvokeCount += 1
yield &_value
}
}
@inlinable
public var projectedValue: T {
get {
getterInvokeCount += 1
return _value
}
_modify {
modifyInvokeCount += 1
yield &_value
}
}
@inlinable
public init(wrappedValue: T) {
self._value = wrappedValue
}
}
class Test {
@MyWrapper var wrapped: Set<Int> = []
var nonWrapped: MyWrapper<Set<Int>> = MyWrapper(wrappedValue: [])
func run() {
for _ in 0..<100 {
wrapped.insert(1)
nonWrapped.wrappedValue.insert(1)
}
// false :(
print("_wrapped.getterInvokeCount == 0:", _wrapped.getterInvokeCount == 0)
// true
print("_wrapped.modifyInvokeCount == 100:", _wrapped.modifyInvokeCount == 100)
// true
print("nonWrapped.getterInvokeCount == 0:", nonWrapped.getterInvokeCount == 0)
// true
print("nonWrapped.modifyInvokeCount == 100:", nonWrapped.modifyInvokeCount == 100)
_wrapped.getterInvokeCount = 0
_wrapped.modifyInvokeCount = 0
for _ in 0..<100 {
$wrapped.insert(1)
}
// false :(
print("_wrapped.getterInvokeCount == 0:", _wrapped.getterInvokeCount == 0)
// true
print("_wrapped.modifyInvokeCount == 100:", _wrapped.modifyInvokeCount == 100)
_wrapped.getterInvokeCount = 0
_wrapped.modifyInvokeCount = 0
for _ in 0..<100 {
_wrapped.wrappedValue.insert(1)
}
// true :)
print("_wrapped.getterInvokeCount == 0:", _wrapped.getterInvokeCount == 0)
// true
print("_wrapped.modifyInvokeCount == 100:", _wrapped.modifyInvokeCount == 100)
}
}
Test().run()
Metadata
Metadata
Assignees
Labels
bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.A deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfThe Swift compiler itselfproperty wrappersFeature: property wrappersFeature: property wrappers