Re: [swift-dev] RFC: bridging peephole for "as" casts

2017-06-13 Thread Jordan Rose via swift-dev


> On Jun 13, 2017, at 16:11, John McCall via swift-dev  
> wrote:
> 
> 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.

Thanks for writing this all down, John. Should returns also be included in 
this? That is:

override func someObjCFunction() -> String {
  return NSMutableString() as String
}

(and, having written that, it seems useful to show code examples for each of 
your cases.)

Jordan

___
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev


Re: [swift-dev] RFC: bridging peephole for "as" casts

2017-06-13 Thread John McCall via swift-dev
> On Jun 13, 2017, at 7:32 PM, Jordan Rose  wrote:
>> On Jun 13, 2017, at 16:11, John McCall via swift-dev > > wrote:
>> 
>> 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.
> 
> Thanks for writing this all down, John. Should returns also be included in 
> this? That is:
> 
> override func someObjCFunction() -> String {
>   return NSMutableString() as String
> }

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.

> (and, having written that, it seems useful to show code examples for each of 
> your cases.)

Sure.

This would avoid the bridging conversions through [View] on the return value of 
the getter:
  let subviews = view.subviews as NSArray

This would not:
  let subviews = view.subviews