[swift-evolution] [Idea] ObjectiveCBridgeable

Russ Bishop xenadu at gmail.com
Tue Mar 8 00:29:08 CST 2016

> On Mar 7, 2016, at 10:36 AM, Douglas Gregor <dgregor at apple.com> wrote:
> There may be some limitations that are inherent to the bridging process, so it’s not clear that we can achieve everything you mention above. As an example, check out my proposal to bridge Objective-C’s lightweight generics into Swift:
> 	http://thread.gmane.org/gmane.comp.lang.swift.evolution/2886 <http://thread.gmane.org/gmane.comp.lang.swift.evolution/2886>
> The content of that proposal isn’t as important as the scope of implementation effort to bridge between two similar-looking but very-differently-implemented features across the languages. It’s likely that other features you’ve mentioned above have similar complexities. That said, I do think it’s possible to extend the bridging mechanism to help alleviate some of the issues you’re describing.

Well the idea is that real bridging is impossible in many cases, so let the Swift type define an arbitrarily different type to represent itself in the world of Objective-C. In some cases this may behave like an opaque value that Objective-C code can’t touch, merely pass around. In others (eg structs/enums) a simpler less type-safe class interface can be provided. Or perhaps enum cases with associated values can map to a class cluster. 

The important part is that the implementer is completely free to design a native Swift API for a feature without actually having to maintain a separate API and test suite.

>> 3. It is up to the API designer to decide if they want to allow construction of wholly new values from Objective-C and how to handle convertibility back to the Swift type in that case
> I’m not sure what you mean by this?

If I define a class (ObjCFizzer) I can choose to keep the initializer private meaning no one can create an instance from Objective-C. I only wanted to mention that explicitly because I can imagine a library author’s objections. In reality this rule just falls out naturally from private/internal visibility anyway.

> FWIW, this method is an anachronism. You can leave it out, because the runtime can now recover this information directly. However, I do suggest that you show
> 	typealias ObjectiveCType = ObjCFizzer
> in your example, so its clear what the mapping is.

Ah thanks, I’ll update it.

> The above isn’t a correct implementation, because it will fatalError return than returning “nil” if the source cannot be bridged.

You’re correct, I meant to do it the other way around. I’ll fix it.

> I had expected ObjCFizzer to be defined in Objective-C. If it can also be defined in Swift, that’s a nontrivial expansion of what bridging currently does.
> Along these lines, I think we’ll need a Clang-side attribute on the Objective-C type to specify what Swift type it bridges to. That’s important for Swift’s Clang importer, because when it sees the Clang type it needs to know whether it’s importing that type directly or bridging to a different type.

First, my assumption is that a type can’t be recursively bridged (the ObjectiveCType cannot itself be bridgeable - the compiler could emit a diagnostic for that).

I guess my second assumption is that the thunk generation happens after the Swift compiler has discovered all the types in the module so whether the ObjectiveCType is defined in Swift or Objective-C doesn’t matter. This may not be true. To be honest I hadn’t considered defining the bridge types in the other direction (an Objective-C API that wants to present a nicer Swift API) but I can see how that would be very useful.

One of the benefits of being able to define the bridge type in Swift is that the bridge type can be a simple @objc type that contains stored properties any arbitrary Swift type. If defining the type in Swift has nontrivial implementation issues we can require the bridged type be defined in Objective-C but it would be nice if we didn’t have to do that.

Good point on the Clang attribute.

>> # TBD / Questions:
>> Should the shape of the protocol change?
> I think the protocol is still basically the right interface, except that getObjectiveCType is no longer necessary. How Objective-C-centric should this protocol be? Should it be possible for (e.g.) the NSInteger-to-Int mapping to be expressible this way? Can a simple C struct be bridged?

In the case of C structs or NS_ENUM, Swift extensions already provide much of the value IMHO. I haven’t actually looked at how the NSInteger typedef gets mapped to Int; do you see value there?

For me the primary motivation is when I’m doing the actual implementation of a feature in Swift, then providing a less type-safe non-generics interface to Objective-C. I’m also looking to a future where we can export free functions to C. Bi-directional exchange with C++ (assuming the committee adopts something like “extern abi” someday) is an interesting case but far out of scope.

> From a proposal perspective, I think it’s important to show the ObjectiveCBridgeable protocol you’re proposing and say what each requirement does. You can grab them directly from the comments, of course, but I suspect that most people haven’t dug into bridging at all.
> If it’s not obvious already, I think this is definitely worthy of a proposal.
> 	- Doug

I’ll write up some of these changes and open a PR.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160307/4f935da0/attachment.html>

More information about the swift-evolution mailing list