> On Sep 12, 2016, at 4:01 PM, Joe Groff <[email protected]> wrote:
>
>
>> On Sep 12, 2016, at 12:24 PM, Paul Cantrell <[email protected]> wrote:
>>
>> In Swift 2, this declaration ensured that callers used only objects as
>> owners:
>>
>> func addObserver(observer: ResourceObserver, owner: AnyObject)
>>
>> In Swift 3, however, an unsuspecting called can pass a struct as an owner.
>> Swift helpfully wraps it in a _SwiftValue, the _SwiftValue is only weakly
>> referenced so it’s immediately deallocated, and so the observer is
>> immediately discarded. It’s nonsensical. The compiler should be able to
>> detect & prevent this.
>>
>> What I want is:
>>
>> func addObserver(observer: ResourceObserver, owner:
>> AnyObjectForRealNotJustAValueWrapper)
>>
>> AFAIK, this is impossible in Swift 3. Or is it?
>
> If you declare the API as taking AnyObject in Swift, this should work
> *better* in Swift 3, since it is no longer possible to pass non-object value
> types to an AnyObject API by implicit conversion. If the API came from
> Objective-C, and uses `id` there, you could perhaps hide the `Any` version
> that gets imported and drop an AnyObject-taking version on top of it in a
> Swift overlay. I agree that we ought to have a more general feature in ObjC
> to say "no, really, this needs to be a reference type", but I think that's
> orthogonal to Charles' original request.
Ah, you’re quite right. Verified it, and it works exactly as you describe. Of
course. I’ve been worrying my little head over nothing. Thanks for clearing
that up!
On investigating, turns out I’d misunderstood the larger situation from a more
localized Swift 3 change in an internal utility class:
/**
A reference that can switched between behaving as a strong or a weak ref
to an object,
and can also hold a non-object type.
- If the value is an object, then...
- ...if strong == true, then StrongOrWeakRef holds a strong reference
to value.
- ...if strong == false, then StrongOrWeakRef holds a weak reference to
value.
- If the value is of a value type, then...
- ...if strong == true, then StrongOrWeakRef holds the structure.
- ...if strong == false, then StrongOrWeakRef immediately discards the
structure.
*/
internal struct StrongOrWeakRef<T> {
private var strongRef: T?
private weak var weakRef: AnyObject?
var value: T? {
return strongRef ?? (weakRef as? T)
}
init(_ value: T) {
strongRef = value
weakRef = value as AnyObject? // ← was `as? AnyObject` in Swift 2
}
var strong: Bool {
get { return strongRef != nil }
set { strongRef = newValue ? value : nil }
}
}
The marked line used to be able to just leave weakRef nil when given a value
type. Now, because the as AnyObject? coercion always succeeds, it performs an
unnecessary heap allocation (I think?) for a _SwiftValue that’s instantly
discarded. The semantics don’t change, just the performance penalty.
That’s a case for Charles’s “is it really an object?” Unless I’m off in the
weeds again. Hardly the end of the world though!
Cheers, P
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution