swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.06k stars 10.33k forks source link

[SR-12629] Capture `self` for `@propertyWrapper` #55073

Open swift-ci opened 4 years ago

swift-ci commented 4 years ago
Previous ID SR-12629
Radar rdar://problem/62894511
Original Reporter xxoo (JIRA User)
Type Improvement
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | | |Labels | Improvement | |Assignee | None | |Priority | Medium | md5: 1c56990dc1af12ccc615fb662b32df10

Issue Description:

This improvement seems to relate https://github.com/apple/swift/pull/25884

Hello dev:

I got a compiler error when implementing a `NormalizeWrapper` for normalizing some `vector` in my OpenGL App.

compiler error:

```swift
...../SwiftGL_examples/01-getting-started/02_Lighting_04_Lighting_maps/Sources/widgets/Camera.swift:9:92: error: use of unresolved identifier 'self'
@NormalizeWrapper\<vec3>(wrappedValue: vec3(0.0, 0.0, -1.0), onValueChanged: { [unowned self] (newValue, oldValue) in
```

Here is the library code:

```swift
import Foundation
import SGLOpenGL
import SGLObjects
import SGLImage
import SGLMath

@propertyWrapper
public struct NormalizeWrapper\<genType> where genType: VectorType, genType.Element: FloatingPointArithmeticType {

private var mVec: genType

private var mOnValueChanged: ((_ newValue: genType, _ oldValue: genType) -> Void)?

public var projectedValue: Self {
get {
self
}
set {
self = newValue
}
}

public init(wrappedValue: genType) {
self.mVec = normalize(wrappedValue)
self.mOnValueChanged = nil
}

public var wrappedValue: genType {
get {
return mVec
}
set {
let oldValue = mVec
if newValue != oldValue {
mVec = normalize(newValue)
if let onValueChanged = mOnValueChanged {
onValueChanged(newValue, oldValue)
}
}
}
}
}

extension NormalizeWrapper {

public init(wrappedValue: genType, onValueChanged: ((_ newValue: genType, _ oldValue: genType) -> Void)? = nil) {
self.mVec = normalize(wrappedValue)
self.mOnValueChanged = onValueChanged
}
}
```

Here is the usage code:

```swift
public class Camera {

@NormalizeWrapper\<vec3>(wrappedValue: vec3(0.0, 0.0, -1.0), onValueChanged: { [unowned self] (newValue, oldValue) in
self.right = normalize(cross(newValue, worldUp))
self.up = normalize(cross(self.right, newValue))
})
public var front: vec3

public var back: vec3 {
-front
}

public private(set) var right: vec3

public var left: vec3 {
-right
}

public private(set) var up: vec3

public var down: vec3 {
-up
}

@NormalizeWrapper\<vec3>
public private(set) var worldUp: vec3

public var position: vec3

public var viewMatrix: mat4 {
SGLMath.lookAt(position, position + front, worldUp)
}

deinit {
//print("Camera # deinit")
}

public init(position: vec3, front: vec3, worldUp: vec3) {
self.position = position
let nFront = normalize(front)
let nWorldUp = normalize(worldUp)
self.right = normalize(cross(nFront, nWorldUp))
self.up = normalize(cross(right, nWorldUp))

self.front = nFront
self.worldUp = nWorldUp
}
}

```

I just want to update the `self.right`and `self.up` vector as soon as the `front` vector be changed. But the `propertyWrapper` can not capture the `self`!

Thanks

beccadax commented 4 years ago

@swift-ci create