Skip to content

SR-0140: Bridge Optionals to nonnull ObjC objects by bridging their payload, or using a sentinel. #4782

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 15, 2016

Conversation

jckarter
Copy link
Contributor

id-as-Any lets you pass Optional to an ObjC API that takes nonnull id, and also lets you bridge containers of Optional to NSArray etc. When this occurs, we can unwrap the value and bridge it so that inhabited optionals still pass into ObjC in the expected way, but we need something to represent none other than the nil pointer. Cocoa provides NSNull as the canonical "null for containers" object, which is the least bad of many possible answers. If we happen to have the rare nested optional T??, there is no precedented analog for these in Cocoa, so just generate a unique sentinel object to preserve the nil-ness depth so we at least don't lose information round-tripping across the ObjC-Swift bridge.

Making Optional conform to _ObjectiveCBridgeable is more or less enough to make this all work, though there are a few additional edge case things that need to be fixed up. We don't want to accept AnyObject?? as an @objc-compatible type, so special-case Optional in getForeignRepresentable.

Implements SR-0140 (rdar://problem/27905315).

@jckarter
Copy link
Contributor Author

@swift-ci Please smoke test

@jckarter
Copy link
Contributor Author

@rjmccall, do you mind reviewing this for 3.0.1?

…ayload, or using a sentinel.

id-as-Any lets you pass Optional to an ObjC API that takes `nonnull id`, and also lets you bridge containers of `Optional` to `NSArray` etc. When this occurs, we can unwrap the value and bridge it so that inhabited optionals still pass into ObjC in the expected way, but we need something to represent `none` other than the `nil` pointer. Cocoa provides `NSNull` as the canonical "null for containers" object, which is the least bad of many possible answers. If we happen to have the rare nested optional `T??`, there is no precedented analog for these in Cocoa, so just generate a unique sentinel object to preserve the `nil`-ness depth so we at least don't lose information round-tripping across the ObjC-Swift bridge.

Making Optional conform to _ObjectiveCBridgeable is more or less enough to make this all work, though there are a few additional edge case things that need to be fixed up. We don't want to accept `AnyObject??` as an @objc-compatible type, so special-case Optional in `getForeignRepresentable`.

Implements SR-0140 (rdar://problem/27905315).
@jckarter jckarter force-pushed the bridging-enhancements branch from d321e8b to cfa9cd9 Compare September 14, 2016 22:50
@jckarter
Copy link
Contributor Author

@swift-ci Please smoke test

@jckarter
Copy link
Contributor Author

@swift-ci Please smoke test Linux

@jckarter jckarter merged commit 3441fe8 into swiftlang:master Sep 15, 2016
@gparker42
Copy link
Contributor

gparker42 commented Sep 15, 2016

Test stdlib/OptionalBridge.swift is failing on i386 iOS simulator.

https://ci.swift.org/job/swift-PR-osx/3631/

/Users/buildnode/jenkins/workspace/swift-PR-osx/branch-master/swift/test/stdlib/OptionalBridge.swift:58:43: error: 'AnyObject' is not convertible to 'NSHashTable<_>'; did you mean to use 'as!' to force downcast?
  expectTrue(unwrappedBridged.isEqual(to: wrappedBridged)
                                          ^
                                                         as! NSHashTable<_>

@jckarter
Copy link
Contributor Author

@DougGregor or @rudkx, any idea where that error would come from? Both unwrappedBridged and wrappedBridged should be AnyObject in that case; is this dynamic lookup going haywire?

@rudkx
Copy link
Contributor

rudkx commented Sep 17, 2016

@jckarter Pretty sure what's happening here is that the only isEqual(to:) in an NSObject-derived class takes an NSHashTable argument. If you remove the argument label it should find NSObjectProtocol's isEqual().

@jrose-apple
Copy link
Contributor

Right, isEqual(to:) is a type-specific method. isEqual(_:) is the real one.

@jckarter
Copy link
Contributor Author

Thanks. I'll try that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants