Open regexident opened 4 years ago
This is a working workaround with its own complications:
protocol FooDelegate {
func foo(_ foo: Foo, bar: Bool)
}
@propertyWrapper
struct CheckedWeakOptional<Value> {
weak var value: AnyObject? = nil
var wrappedValue: Value? {
get {
if self.value == nil {
print("Expected value, found nil")
}
return self.value as? Value
}
set {
self.value = newValue as AnyObject
}
}
}
class Foo {
@CheckedWeakOptional var delegate: FooDelegate?
func bar() {
print(type(of: self), #function)
self.delegate?.foo(self, bar: true)
}
}
struct StructFooDelegate: FooDelegate {
func foo(_ foo: Foo, bar: Bool) {
print(type(of: self), #function)
}
}
class ClassFooDelegate: FooDelegate {
func foo(_ foo: Foo, bar: Bool) {
print(type(of: self), #function)
}
}
let foo = Foo()
let classDelegate = ClassFooDelegate()
let structDelegate = StructFooDelegate()
foo.bar()
// Output:
// Foo bar()
// Expected value, found nil
print()
foo.delegate = classDelegate
foo.bar()
// Output:
// Foo bar()
// ClassFooDelegate foo(_:bar:)
print()
foo.delegate = structDelegate
foo.bar()
// Output:
// Foo bar()
// Expected value, found nil
I wonder if the right answer is going to be a built-in constraint ("layout constraint" in Swift compiler parlance) that's weaker than AnyObject: "reference-counted and class-bound in some way". We don't get the "single retainable pointer" optimization, but it would allow arbitrary weak references without having to cast in and out. Meanwhile, that's another possible workaround:
@propertyWrapper
public struct CheckedOptional<Value> {
private weak var value: AnyObject? // NEW
public init() {
self.value = nil
}
public var wrappedValue: Value? {
get {
if self.value == nil {
print("Expected value, found nil")
}
return self.value as! Value? // NEW
}
set {
self.value = newValue
}
}
}
cc @slavapestov, @jckarter
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: d237cea5fceb17d115a2a19985992a57Issue Description:
Let's assume one wants to wrap an optional value in a `@propertyWrapper`, so that on every read access a message is logged in case the value is `nil`.
Easy peasy:
Now let's assume one wanted to change
into
which fails due to:
Now changing
to
leads to this error:
Here is the full code
Note that the whole thing does compile once one changes
to
which unfortunately defeats the whole point of having a protocol in the first place and as such is not a feasible solution.