<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 23, 2016, at 12:21 AM, Russ Bishop <<a href="mailto:xenadu@gmail.com" class="">xenadu@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Mar 21, 2016, at 9:41 AM, Douglas Gregor <<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 9, 2016, at 12:26 PM, Russ Bishop via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">An official proposal PR has been opened on this: <a href="https://github.com/apple/swift-evolution/pull/198" class="">https://github.com/apple/swift-evolution/pull/198</a><div class=""><br class=""></div><div class="">It includes clarifications, a few changes, and some better examples.</div></div></div></blockquote></div></div></div></blockquote><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class=""><pre class="" style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 16px; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);"><code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;"> /// 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</code></pre><div class="">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.</div></div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I’ve added a section to the proposal to call out that it is intended for conformance to be conditional in some cases (eg Array), and a small explanation of what to do and a code example. It’s a bit unwieldy but workable until we have conditional conformance.</div></div></div></blockquote><div><br class=""></div><div>Great. The suggestion to use an extension won’t actually work:</div><div><br class=""></div><div><pre style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 16px; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);" class=""><code style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;" class=""> /// A default implementation returns `true`. If a Swift type is
/// generic and should only be bridged for some type arguments,
/// provide alternate implementations in extensions
/// and return `false` in those cases.
///
/// struct Foo<T>: ObjectiveCBridgeable { ... }
/// extension Foo where T: NonBridgedType {
/// static func isBridgedToObjectiveC() -> Bool {
/// return false
/// }
/// }</code></pre><div class="">because you don’t get dynamic dispatching based on T. Instead, you want one implementation of isBridgedToObjectiveC that does a dynamic check, e.g.,</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><div class=""><font face="Menlo" class="">struct Foo<T>: ObjectiveCBridgeable {</font></div></div></div><div><div><div class=""><font face="Menlo" class=""> static func isBridgedToObjectiveC() -> Bool {</font></div></div></div><div><div><div class=""><font face="Menlo" class=""> return !(T is NonBridgedType)</font></div></div></div><div><div><div class=""><font face="Menlo" class=""> }</font></div></div></div><div><div><div class=""><font face="Menlo" class="">}</font></div></div></div></blockquote><div><div><div class=""> </div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class=""><pre class="" style="box-sizing: border-box; overflow: auto; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; margin-top: 0px; margin-bottom: 16px; line-height: 1.45; padding: 16px; background-color: rgb(247, 247, 247); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-wrap: normal; color: rgb(51, 51, 51);"><code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; padding: 0px; margin: 0px; background-color: transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal; border: 0px; display: inline; line-height: inherit; word-wrap: normal;"> /// 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)</code></pre><div class="">FWIW, implementing this required a new “unconditional” entry point used by the compiler:</div></div><div class=""><br class=""></div><div class=""><div class=""> static func _unconditionallyBridgeFromObjectiveC(source: _ObjectiveCType?)</div><div class=""> -> Self</div></div><div class=""><br class=""></div><div class="">It can get a default implementation, and should be a non-failable initializer.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I’ve updated the proposal to add this. The default implementation of "init(unconditionallyBridgedFromObjectiveC: ObjectiveCType?)" just calls the fallible initializer and aborts if anything goes wrong. Default implementation of “unconditionallyBridgeFromObjectiveC(source: ObjectiveCType?)” calls the initializer. My guess is most types will probably just accept the default behavior.</div></div></div></blockquote><div><br class=""></div>Yes, I suspect you’re right that most types will use the default.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""></div><div class="">I assume this is a static function to avoid allocating memory by calling the initializer directly for each element, given the point is to defer the work? I wonder if we can skip the static though and just call the initializer directly? It would simplify the protocol a tiny bit.</div></div></div></blockquote><div><br class=""></div><div>From an implementation perspective, the entry point for an initializer in a protocol handles the allocation itself. It’s a static function because it was easy to implement that way and the actual definitions get a bit more flexibility in how they can come up with the object (since we don’t have factory initializers).</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><div class=""><span class="" style="background-color: rgb(255, 255, 255);"><span class="Apple-tab-span" style="white-space: pre;">        </span>4. </span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">The </span><code class="" style="color: rgb(51, 51, 51); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">ObjectiveCType</code><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">must be defined in Swift. If a</span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><code class="" style="color: rgb(51, 51, 51); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">-swift.h</code><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">header is generated, it will include a</span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><code class="" style="color: rgb(51, 51, 51); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">SWIFT_BRIDGED()</code><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">macro where the parameter indicates the Swift type with which the</span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><code class="" style="color: rgb(51, 51, 51); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">ObjectiveCType</code><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">bridges. The macro will be applied to the</span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><code class="" style="color: rgb(51, 51, 51); box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">ObjectiveCType</code><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"> </span><span class="" style="color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);">and any subclasses.</span></div></div><div class=""><div class=""><br class=""></div></div><div class="">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:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>(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.</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>(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.</div><div class=""><br class=""></div><div class=""><br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">I mostly hadn’t really considered the implications but I see the value and I trust your assessment; I removed the restriction and reworded the whole section.</div></div></div></blockquote><div><br class=""></div>Looks good, thanks!</div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><br class=""></div><div class=""><ol class="" style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 16px; color: rgb(51, 51, 51); font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; font-size: 16px; background-color: rgb(255, 255, 255);"><li class="" style="box-sizing: border-box;">(This was #5) It is an error for bridging to be ambiguous.</li><li class="" style="box-sizing: border-box;"><ol class="" style="box-sizing: border-box; padding-left: 2em; margin-top: 0px; margin-bottom: 0px; list-style-type: lower-roman;"><li class="" style="box-sizing: border-box;">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.</li><li class="" style="box-sizing: border-box;">The compiler must emit a diagnostic when it detects two Swift types attempting to bridge to the same <code class="" style="box-sizing: border-box; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; padding: 0.2em 0px; margin: 0px; background-color: rgba(0, 0, 0, 0.0392157); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px;">ObjectiveCType</code>.</li></ol></li></ol></div><div class="">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. </div></div></div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Perhaps the rule should simply be that any Objective-C API imported that has ambiguity is imported as the Objective-C type without automatic bridging support. The compiler can continue to import Int and friends with special magic. Creating an ambiguity just leaves you to resolve the problem manually? The rule would be something like "omitting the SWIFT_BRIDGED() attribute from ObjC //or// multiple Swift types bridging to the same ObjC type" turns off automatic thunk generation but bridged collections will still call the protocol where appropriate.</div></div></div></blockquote><div><br class=""></div><div>Yeah. Thinking about it a bit further, I like your rule basically as you’ve stated it, because having two _ObjectiveCBridgeable conformances mapping to the same type is a problem the user should have to resolve. I guess I’m just looking for something small to indicate that a direct mapping of the representation (e.g., NSInteger -> Int) supersedes the _ObjectiveCBridgeable conformance when mapping APIs between Objective-C and Swift.</div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">An update has been posted to <a href="https://github.com/russbishop/swift-evolution/blob/master/proposals/0000-objectivecbridgeable.md" class="">https://github.com/russbishop/swift-evolution/blob/master/proposals/0000-objectivecbridgeable.md</a></div></blockquote><div><br class=""></div>Thanks!</div><div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Would you prefer if I did / did not add your name to the proposal? I feel guilty taking all the credit.</div></blockquote><br class=""></div><div>I don’t have a strong preference. Feel free to add my name if you’d like. I really appreciate your work on driving this proposal forward!</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div><br class=""></div><br class=""></body></html>