> https://github.com/apple/swift-evolution/blob/master/proposals/0058-objectivecbridgeable.md
> But then, these *are* intended to be full-width type conversions,
> are they not? Why not these:
>
> init?(_ source: ObjectiveCType)
> init(_ source: ObjectiveCType?)
>
> ? If any of these transformations are wrong, it would good to have
> a rationale as to why.
I really don't like these two differing only by the optionality of their
argument and return type, especially if they're going to have *no* argument
label, which will make them look very attractive. And the unconditional one has
many strange semantics—the extra layer of optionality on the argument, the fact
that it may *lazily* crash if you access a sub-object which isn't permitted,
etc. So I would at least label that one:
init?(_ source: ObjectiveCType)
init(forced source: ObjectiveCType?)
I'm also a little worried about having an `init?(_:)` when a particular
conversion might reasonably always succeed. The lack of a label will imply to
users that this is something they can use directly;
> 3. Is this proposal introducing a backdoor people can exploit to create
> user-defined implicit conversions? If so, shouldn't that worry us?
This proposal reads to me like it permits conversions by casting, but not by
simply using one type where another belongs.
> 4. This proposal should probably support creating a type that only
> bridges *from* Objective-C, to handle bridging mutable Objective-C
> classes without an immutable base class to value types (anything else
> breaks one of the languages' expectations of value or reference
> semantics). This suggests a hierarchy of two protocols might be
> warranted.
I agree.
Here's an alternative design. It does a few things:
* Splits bridging from and bridging to Objective-C so they can be applied
independently.
* Splits conditional and unconditional bridging from Objective-C.
* Explicitly marks Objective-C types with their Swift equivalents, even in
Swift, to make it clear that each Objective-C type bridges to exactly one Swift
type, and which type that is. (This allows you to have multiple conversions
between various Swift types and a single Objective-C type, while explicitly
specifying which one, if any, should be used when translating Objective-C APIs
to Swift.)
I'm using the proposed SE-0041 protocol naming conventions
(https://github.com/apple/swift-evolution/blob/master/proposals/0041-conversion-protocol-conventions.md)
to name the protocols. I'm also assuming the presence of conditional
conformances and where clauses on associated types; these protocols would have
to be temporarily hobbled to work within the type system's current capabilities.
/// Conforming types can be cast from Self to ObjectiveCType using `as`
(or a subtype using `as?`
/// or `as!`), and Swift APIs taking or returning Self are exposed to
Objective-C as ObjectiveCType.
protocol ObjectiveCRepresentable {
associatedtype ObjectiveCType: AnyObject
func bridged() -> ObjectiveCType
}
/// Conforming types can be cast from ObjectiveCType or a subtype to
Self using `as?` or `as!`.
///
/// -SeeAlso: ObjectiveCUnconditionallyCreatable, ObjectiveCBridgeable
protocol ObjectiveCCreatable {
associatedtype ObjectiveCType: AnyObject
init?(_ source: ObjectiveCType)
init(forced source: ObjectiveCType?)
}
/// Conforming types can be cast from UnconditionalObjectiveCType to
Self using `as`.
///
/// -Note: A type can conform to both this protocol and
ObjectiveCCreatable to
/// allow both an unconditional exact cast and a
conditional inexact one.
/// For instance, Array can have ObjectiveCType =
NSArray<AnyObject>
/// and UnconditionalObjectiveCType = NSArray<T>.
protocol ObjectiveCUnconditionallyCreatable {
associatedtype UnconditionalObjectiveCType: AnyObject
init(_ source: UnconditionalObjectiveCType?)
}
/// Conforming types are translated from Self to SwiftType in APIs
imported from Objective-C.
///
/// -Note: Objective-C headers can apply this protocol to their
classes using the
/// SWIFT_BRIDGED("SwiftType") attribute.
/// -Remark: This could instead be indicated with a Swift-side
attribute.
protocol ObjectiveCBridgeable: class {
associatedtype SwiftType: ObjectiveCUnconditionallyCreatable
where SwiftType.UnconditionalObjectiveCType == Self
}
Interestingly, another alternative would be to remove the bridging semantic
from ObjectiveCRepresentable and put it in a subprotocol:
/// Conforming types can be cast from Self to ObjectiveCType using `as`
(or a subtype using `as?`
/// or `as!`).
protocol ObjectiveCRepresentable { … }
/// Conforming types will be translated from Self to ObjectiveCType in
APIs exported to Objective-C
protocol SwiftToObjectiveCBridgeable: ObjectiveCRepresentable {}
/// Conforming types are translated from Self to SwiftType in APIs
imported from Objective-C.
///
/// -Note: Objective-C headers can apply this protocol to their
classes using the
/// SWIFT_BRIDGED("SwiftType") attribute.
protocol ObjectiveCToSwiftBridgeable: class {
associatedtype SwiftType: ObjectiveCUnconditionallyCreatable
where SwiftType.UnconditionalObjectiveCType == Self
}
Then the Representable protocol and the two Creatable protocols are no longer
Objective-C-specific—they simply indicate that a type can be cast to an
equivalent object type. We can then make them into ObjectRepresentable,
ObjectCreatable, and ObjectUnconditionalCreatable. (This is good because we
will presumably want to continue, for instance, casting NSNumber to Int in
Corelibs Foundation code.)
--
Brent Royal-Gordon
Architechies
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution