> 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

Reply via email to