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.
A bridging conversion 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 bridged to the foreign type.
Bridging conversions are performed for three reasons in Swift:
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".
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.
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.
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.
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.
The proposal is to apply a guaranteed syntactic "peephole" to eliminate
bridging conversions that arise from reason #3. Specifically:
No bridging conversions will be performed if:
- a call, property reference, or subscript reference is the immediate
syntactic
operand of an "as" cast to a type compatible with the foreign return,
property,
or subscript element type or
- a call argument, right operand of an assignment to a property reference,
or
right operand of an assignment to a subscript reference is an "as" cast
from a
type compatible with the foreign parameter, property, or subscript
element type.
Two types are "compatible" if there is a simple subclass or class-protocol
relationship
between the underlying non-optional types.
We believe that this rule is easy and intuitive enough to understand that it
will not cause substantial problems.
John.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev