> On Mar 9, 2016, at 12:26 PM, Russ Bishop via swift-evolution 
> <[email protected]> wrote:
> 
> An official proposal PR has been opened on this: 
> https://github.com/apple/swift-evolution/pull/198 
> <https://github.com/apple/swift-evolution/pull/198>
> 
> It includes clarifications, a few changes, and some better examples.

FWIW, I’ve implemented much of this proposal as a series of compiler cleanups. 
It introduces a few tweaks to the _ObjectiveCBridgeable protocol that were 
necessary to generalize (and de-special-case) the 
NSString/NSArray/NSDictionary/NSSet bridging, but it’s still considered an 
implementation detail. So, some comments on the proposal itself…


/// A type adopting `ObjectiveCBridgeable` will be exposed
/// to Objective-C as the type `ObjectiveCType`
public protocol ObjectiveCBridgeable: _ObjectiveCBridgeable {
    associatedtype ObjectiveCType : AnyObject
    associatedtype _ObjectiveCType = ObjectiveCType
I think we should just say that ObjectiveCBridgeable replaces 
_ObjectiveCBridgeable, and only have the first associated type. (You actually 
wanted a typealias anyway, I think).

    /// Returns `true` iff instances of `Self` can be converted to
    /// Objective-C.  Even if this method returns `true`, a given
    /// instance of `Self._ObjectiveCType` may, or may not, convert
    /// successfully to `Self`.
    ///
    /// A default implementation returns `true`.
    @warn_unused_result
    static func isBridgedToObjectiveC() -> Bool
It’s probably worth saying why someone might override this method: usually, 
it’s because the Swift type is generic and it only makes sense to bridge for 
some type arguments. Granted, there is no way to communicate this information 
to the compiler, which is a bit of a hole in the design. For example, Array<T> 
only bridges to NSArray when T is itself representable in Objective-C. We 
really need conditional conformances to for this part of the feature to work 
properly.

    /// Try to construct a value of the Self type from
    /// an Objective-C object of the bridged class type.
    ///
    /// If the conversion fails this initializer returns `nil`.
    init?(bridgedFromObjectiveC: ObjectiveCType)
FWIW, implementing this required a new “unconditional” entry point used by the 
compiler:

  /// Bridge from an Objective-C object of the bridged class type to a
  /// value of the Self type.
  ///
  /// This bridging operation is used for unconditional bridging when
  /// interoperating with Objective-C code, either in the body of an
  /// Objective-C thunk or when calling Objective-C code, and may
  /// defer complete checking until later. For example, when bridging
  /// from `NSArray` to `Array<Element>`, we can defer the checking
  /// for the individual elements of the array.
  ///
  /// \param source The Objective-C object from which we are
  /// bridging. This optional value will only be `nil` in cases where
  /// an Objective-C method has returned a `nil` despite being marked
  /// as `_Nonnull`/`nonnull`. In most such cases, bridging will
  /// generally force the value immediately. However, this gives
  /// bridging the flexibility to substitute a default value to cope
  /// with historical decisions, e.g., an existing Objective-C method
  /// that returns `nil` to for "empty result" rather than (say) an
  /// empty array. In such cases, when `nil` does occur, the
  /// implementation of `Swift.Array`'s conformance to
  /// `_ObjectiveCBridgeable` will produce an empty array rather than
  /// dynamically failing.
  static func _unconditionallyBridgeFromObjectiveC(source: _ObjectiveCType?)
      -> Self

It can get a default implementation, and should be a non-failable initializer.

    static func _getObjectiveCType() -> Any.Type {
        return ObjectiveCType.self
    }
This was an implementation hack; it’s gone now.

Expose the protocol ObjectiveCBridgeable
Any type adopting ObjectiveCBridgeable will gain conformance to 
_ObjectiveCBridgeable
As noted earlier, I think there should just be one protocol here, 
ObjectiveCBridgeable.

        4. The ObjectiveCType must be defined in Swift. If a -swift.h header is 
generated, it will include a SWIFT_BRIDGED()macro where the parameter indicates 
the Swift type with which the ObjectiveCType bridges. The macro will be applied 
to the ObjectiveCType and any subclasses.

This is unnecessarily restrictive, and eliminates the “make my Objective-C 
class bridge into a Swift value type” case that (for example) the compiler 
already does for String/Array/Dictionary/Set. I think there are two cases:

        (a) The ObjectiveCType is defined in Objective-C. It must be an 
Objective-C class with the attribute swift_bridge(“Bar”), where “Bar” is the 
name of the bridged Swift type.
        (b) The ObjectiveCType is defined in Swift, in which case it must be an 
@objc class. When emitting the generated header, the appropriate swift_bridge 
attribute will be added to the @interface declaration.



(This was #5) It is an error for bridging to be ambiguous.
A Swift type may bridge to an Objective-C base class, then provide different 
subclass instances at runtime but no other Swift type may bridge to that base 
class or any of its subclasses.
The compiler must emit a diagnostic when it detects two Swift types attempting 
to bridge to the same ObjectiveCType.
This is a tricky area. Currently, Int/Float/Double/Bool/CGFloat/UInt all have 
_ObjectiveCBridgeable conformances, although those conformances only really 
kick in at runtime (e.g., when dynamically casting an [AnyObject] or [NSNumber] 
to [Int] or [Double] with as? or matching a switch case). They would run afoul 
of this rule. However, this rule does generally make sense: if two Swift types 
have the same ObjectiveCType, we won’t know how to map an Objective-C API back 
into Swift. Those numeric types only work because they are trivially mapped 
between Swift and (Objective-)C; they don’t need to go through the 
_ObjectiveCBridgeable conformance. 

On the other hand, the greater ambiguity problem is if there are two 
conformances to ObjectiveCBridgeable on the same type; that’s already covered 
by Swift’s rules about multiple conformances.

(This was #6) The Swift type and ObjectiveCType must be defined in the same 
module
Yes, absolutely. If the ObjectiveCType comes from Objective-C, then it must 
come from the same-named Objective-C module.

Under “Alternatives considered”, there is a typo “fesible”.

I’ve been assuming we’re only allowed to bridge with Objective-C classes 
(whether they are defined in Swift or Objective-C), but Swift also has @objc 
enums now… I assume you don’t intend @objc enums to be part of this, so I think 
it makes sense to be explicit about the limitation to classes.

        - Doug


_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to