> On Sep 29, 2016, at 10:16 AM, Joe Groff via swift-evolution
> <[email protected]> wrote:
>
> In the discussion around SE-0139 (bridging NSNumber and NSValue), many people
> pointed out that it's common in ObjC to use NSNumbers holding enum constants
> in Cocoa containers. Many ObjC interfaces look something like this:
>
> /// A washing machine.
> @interface QXWashingMachine
>
> /// Wash cycles supported by the washing machine.
> typedef NS_ENUM(NSInteger, QXWashCycle) {
> QXWashNormal,
> QXWashDelicates,
> QXWashLinens,
> };
>
> /// Perform a sequence of wash cycles. Takes an NSArray of QXWashCycle
> constants passed
> /// as NSNumbers.
> - (void)performWashCycles:(NSArray *)cycles;
>
> @end
>
> In ObjC, you can call this API like this:
>
> [washingMachine performWashCycles:@[
> @(QXWashLinens),
> @(QXWashDelicates),
> ]];
>
> In Swift 3, the equivalent code will compile, but fail at runtime, because
> the enum type falls back to opaque object bridging instead of using NSNumbers:
>
> // Fails at runtime, because WashCycle constants don't implicitly
> bridge to NSNumber
> washingMachine.perform(washCycles: [WashCycle.linens,
> WashCycle.delicates])
>
> so you have to know to get the `rawValue`s out first:
>
> // Fails at runtime, because WashCycle constants don't implicitly
> bridge to NSNumber
> washingMachine.perform(washCycles: [WashCycle.linens.rawValue,
> WashCycle.delicates.rawValue])
>
> We encountered similar problems last year as we developed the `swift_newtype`
> ObjC feature last year, which enabled us to import some stringly-typed ObjC
> APIs with stronger types in Swift. A type like `Notification.Name`, which
> represents a set of NSString constants, is imported to be RawRepresentable as
> String and also to bridge to Objective-C as one, by having the compiler
> implicitly generate a conformance to the internal _ObjectiveCBridgeable
> protocol for it. We could conceivably do one of the following things:
>
> - Have the compiler generate a bridging conformance for imported NS_ENUM and
> NS_OPTIONS types, and perhaps also for @objc enums defined in Swift, like we
> do for newtypes.
> - Alternatively, we could say that *anything* with a RawRepresentable
> conformance bridges to ObjC as its rawValue.
>
> The second one is conceptually appealing to me, since RawRepresentable is
> already something newtypes, enums, and option sets have in common in Swift,
> but I think it may be too lax—it would effectively make RawRepresentable the
> user interface to Objective-C bridging, which I'm not sure is something we
> want. Limiting the bridging behavior to @objc enums and imported option sets
> limits the impact, though there are still tradeoffs to consider:
>
> - Adding any new bridging behavior has the potential to break existing code
> that relies on the current opaque object bridging. We tell people not to do
> that, of course, but that's no guarantee that people don't.
> - As with newtypes, the bridged Objective-C representation loses type
> information from Swift, meaning that dynamic casts potentially need to become
> "slushier". Swift maintains the distinction between Notification.Name and
> String, for example, but once a value of either type has been bridged to
> NSString, the distinction is lost, so we have to allow casts from NSString
> back to either String or Notification.Name. If we bridge enums and option
> sets, we would similarly lose type information once we go to NSNumber. We can
> in some cases mitigate this for class clusters like NSString or NSNumber by
> using our own subclasses that preserve type info, which can at least preserve
> type info for Swift-bridged objects, though we can't do this universally for
> all Cocoa-sourced objects.
Personally, I consider the first one to be a fairly-low-risk extension to
SE-0139 that’s borderline bug-fix. We already know that those types have weak
numeric representations in Objective-C because they come from Objective-C, so
losing some of the type info by bridging to Objective-C is (IMO) falls out of
having strong types in Swift for weaker types in Objective-C.
The second one makes me a little nervous, I think because it weakens typing for
types defined in Swift. These types don’t naturally have Objective-C
counterparts, so if we’re going to weaken the types, it feels like we should
only do so via some explicit conformance (e.g., to a publicly-available form of
_ObjectiveCBridgeable).
- Doug
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution