<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=""><div><blockquote type="cite" class=""><div class="">On Jun 13, 2017, at 7:32 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 13, 2017, at 16:11, John McCall via swift-dev <<a href="mailto:swift-dev@swift.org" class="">swift-dev@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">So, there's a longstanding issue that we're planning to fix in Swift 4, and I want to both make sure that the plan is documented publicly and give people a chance to disagree with it.<div class=""><br class=""></div><div class="">A <b class="">bridging conversion</b> is a conversion between a Swift type and a foreign type (C / ObjC / whatever) which can represent the same set of values. For example, there are bridging conversions from Swift.String to ObjC's NSString and vice-versa. When there two-way conversions like this, we say that the Swift type is<b class=""> bridged to</b> the foreign type.</div><div class=""><br class=""></div><div class="">Bridging conversions are performed for three reasons in Swift:</div><div class=""><br class=""></div><div class="">1. You can always request a bridging conversion with an unconditional "as" cast. For example, if myString is a String, you can convert it to NSString by writing "myString as NSString".</div><div class=""><br class=""></div><div class="">2. Certain bridging conversions can be introduced as implicit conversions. (This is perhaps a mistake.) For example, CFString and NSString are considered different types, but they will implicitly convert to each other.</div><div class=""><br class=""></div><div class="">3. Bridging conversions are done "behind the scenes" when using an imported declaration that has been given a type that does not match its original type. For example, an Objective-C method that returns an NSString will be imported as returning a String; Swift will implicitly apply a bridging conversion to the true return value in order to produce the String that the type system has promised.</div><div class=""><br class=""></div><div class="">Bridging conversions are not always desirable. First, they do impose some performance overhead which the user may not want. But they can also change semantics in unwanted ways. For example, in certain rare situations, the reference identity of an NSString return value is important — maybe it's actually a persistent NSMutableString which should be modified in-place, or maybe it's a subclass which carries additional information. A pair of bridging conversions from NSString to String and then back to NSString is likely to lose this reference identity. In the current representation, String can store an NSString reference, and if the String is bridged to NSString that reference will be used as the result; however, the bridging conversion from NSString does not directly store the original NSString in the String, but instead stores the result of invoking +copy on it, in an effort to protect against the original NSString being somehow mutable.</div><div class=""><br class=""></div><div class="">Bridging conversions arising from reasons #1 and #2 are avoidable, but bridging conversions arising from reason #3 currently cannot be eliminated without major inconvenience, such as writing a stub in Objective-C. This is unsatisfactory. At the same time, it is not valid for Swift to simply eliminate pairs of bridging conversions as a matter of course, precisely because those bridging conversions can be semantically important. We do not want optimization settings to be able to affect things as important as whether a particular NSString is mutable or not.</div><div class=""><br class=""></div><div class="">The proposal is to apply a guaranteed syntactic "peephole" to eliminate bridging conversions that arise from reason #3. Specifically:</div><div class=""><br class=""></div><div class=""> No bridging conversions will be performed if:</div><div class=""> - a call, property reference, or subscript reference is the immediate syntactic</div><div class=""> operand of an "as" cast <i class="">to</i> a type compatible with the foreign return, property,</div><div class=""> or subscript element type or</div><div class=""> - a call argument, right operand of an assignment to a property reference, or</div><div class=""> right operand of an assignment to a subscript reference is an "as" cast <i class="">from</i> a</div><div class=""> type compatible with the foreign parameter, property, or subscript element type.</div><div class=""> Two types are "compatible" if there is a simple subclass or class-protocol relationship</div><div class=""> between the underlying non-optional types.</div><div class=""><br class=""></div><div class="">We believe that this rule is easy and intuitive enough to understand that it will not cause substantial problems.</div></div></div></blockquote><br class=""></div><div class="">Thanks for writing this all down, John. Should returns also be included in this? That is:</div><div class=""><br class=""></div><div class="">override func someObjCFunction() -> String {</div><div class=""> return NSMutableString() as String</div><div class="">}</div></div></div></blockquote><div><br class=""></div>Hmm. We're not in a position to make this guarantee easily, because this isn't inherently a foreign method in the same way that an imported API is. Maybe we can find a way to promise that later? Or maybe we could just allow such overrides to use the foreign types instead of the native ones.</div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">(and, having written that, it seems useful to show code examples for each of your cases.)</div></div></div></blockquote><div><br class=""></div></div>Sure.<div class=""><div class=""><br class=""></div><div class="">This would avoid the bridging conversions through [View] on the return value of the getter:</div><div class=""> let subviews = view.subviews as NSArray</div><div class=""><br class=""></div><div class="">This would not:</div><div class=""> let subviews = view.subviews</div><div class=""> let nsSubviews = subviews as NSArray</div><div class=""><br class=""></div><div class="">This would avoid the bridging conversion through [CIFilter] on the argument to the setter:</div><div class=""> view.backgroundFilters = nsFilters as [CIFilter]</div><div class=""><br class=""></div><div class="">This would not:</div><div class=""> let filters = nsFilters as [CIFilter]</div><div class=""> view.backgroundFilters = filters</div><div class=""><br class=""></div><div class="">John.</div><div class=""><br class=""></div></div></body></html>