[swift-evolution] [Pitch] SE-0083 revisited: removing bridging behavior from `as`/`is`/`as?` casts

Joe Groff jgroff at apple.com
Thu Mar 2 18:24:35 CST 2017

> On Mar 2, 2017, at 3:09 PM, Jaden Geller <jaden.geller at gmail.com> wrote:
> +1. I’ve always found the bridging casting behavior confusing. Definitely would agree with removing it—especially given the interop problems—but only if a good solution was found for imported APIs.
> With `NSNumber`-involving APIs, I think it might be reasonable to add an Objective-C annotation to specify what numeric type ought to be used (instead of Any). For example, `-(NSNumber<UInt32> *) foo` is a straw-man syntax for specifying that a number should be imported as `UInt32` in Swift.

That might be a nice ObjC addition, but I think we could pursue that independently.

> What other APIs involve this dynamic through-`Any` bridging behavior? It might make sense to make a comprehensive list. Another I can think of is `NSJSONSerialization`. It would be much more difficult to remove bridging behavior here without new language features… Additionally, NSNumber is still problematic—what should be the numeric type of a JSON number? If only we had integer and floating point existentials…

In general, anywhere you get an `id` behavior—return values, block callback inputs, and yeah, untyped NSArrays and NSDictionarys. In the case of JSON, you might be able to use Double, but for the full range of types plists support, IMO you arguably ought to work directly with the NSNumber interface. That's likely the only implementation that'd make sense in corelibs foundation, for instance. (Maybe with the new integer protocols we could introduce an `AnyNumeric` type-erased container…)

> Perhaps Objective-C APIs that return `id`, when called from Swift, ought to eagerly perform bridging for the boxed value into the respective Swift type? Then `as` would no longer perform this weird behavior; it would just happen by default for all values return from Objective-C APIs. No need to store an extra bit on the existential and introduce inconsistent behavior… 

The problem is that we can't know, without further input from the compiler, what bridging is needed, if any. The interface may intend to provide an NSNumber, or an NSString backed by NSTextStorage or Core Data, or something like that, for which you wouldn't want to go through the bridge.

> There obviously ought to be a way to opt out of this if you want the original type. Perhaps the compiler could detect conversions back to Objective-C types are optimize away the round-trip? For example, `try! JSONSerialization.jsonObject(with: data)` would be implicitly converting to a Swift type (wrapped in an `Any`) while `NSString(try! JSONSerialization.jsonObject(with: data) as! String)` would skip the roundtrip conversion via the optimizer.

The compiler already does some of this. If you pass a value type as an `Any` parameter, it will bridge directly to the parameter's bridged object type instead of going through Any and dynamically bridging first.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170302/71e2cf8c/attachment.html>

More information about the swift-evolution mailing list