[swift-evolution] Pitch: really_is and really_as operators

Paul Cantrell cantrell at pobox.com
Mon Sep 12 16:24:41 CDT 2016


> On Sep 12, 2016, at 4:01 PM, Joe Groff <jgroff at apple.com> wrote:
> 
> 
>> On Sep 12, 2016, at 12:24 PM, Paul Cantrell <cantrell at pobox.com> 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

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160912/6484cfad/attachment.html>


More information about the swift-evolution mailing list