> On Mar 23, 2016, at 11:49 AM, Douglas Gregor <dgre...@apple.com> wrote:
>> 
> 
> Great. The suggestion to use an extension won’t actually work:
> 

Doh. Thanks for catching that, I pushed a fix.



>   
>> 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.
> 
> 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).
 
Good point about the factory initializers. I’ve been trying to keep the whole 
“class cluster” situation in mind. I wonder if there should be an equivalent 
static function for the conditional bridging for similar reasons?



>>> 
> 
>>> (This was #5) It is an error for bridging to be ambiguous.
>>> 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.
>>> The compiler must emit a diagnostic when it detects two Swift types 
>>> attempting to bridge to the same ObjectiveCType.
>>> 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. 
>> 
>> 
>> 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.
> 
> 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.
> 


I added a separate section on Ambiguity and what the behavior is. I think you 
should be able to resolve ambiguity by casting so I went ahead and put that in. 
An example:

//Bar and Foo bridge to SomeObjectiveCType
struct Bar<T>: ObjectiveCBridgeable { }
struct Foo<T>: ObjectiveCBridgeable { }

class API {
    let foo: Foo<Int>
    func objCVersionOfAFunction(obj: SomeObjectiveCType) -> SomeObjectiveCType {
        let x = obj as! Bar<Int>
        // We've told the compiler which protocol impl to call
        return foo as! SomeObjectiveCType
    }
}

Any problems with this approach? It makes handling the ambiguous or manual 
bridging case relatively straightforward, though there may be objections to 
using casting this way. [Be careful, I still mourn the loss of @conversion so 
I’m biased :)]


`NSInteger` is already imported as `Int` from Objective-C right? I assume a 
Clang attribute is specifying that somewhere but there wouldn’t be any 
ambiguity on the Swift side during import. I could definitely see having an 
attribute to declare that this specific parameter or return value should bridge 
to a specific Swift type (this NSNumber should import as Int) but that’s a lot 
of work and may be worth a separate proposal.

It seems like the problem is going the other direction: you want to materialize 
this parameter or whatever as `NSInteger` instead of the default `NSNumber *` 
but only when directly bridged, not inside collections. There’s no existing 
Objective-C header to tell us what to do. I’m not sure how we can resolve this 
without a Swift attribute to tell the compiler because the handling of it would 
be specific to each declaration. 

We could just  say that we aren’t going to let people have that level of 
granularity. Then just introduce a BuiltInBridgeable protocol that supersedes 
ObjectiveCBridgeable. A type adopting both will cause the compiler to prefer 
the built-in protocol when generating a bridging header, but the collection 
types can ignore that and just use ObjectiveCBridgeable. Presumably the 
BuiltInBridgeable protocol would just have an associated type to indicate that 
the bits are directly mapped to BuiltIn.Word or whatever.



>> An update has been posted to 
>> https://github.com/russbishop/swift-evolution/blob/master/proposals/0000-objectivecbridgeable.md
>>  
>> <https://github.com/russbishop/swift-evolution/blob/master/proposals/0000-objectivecbridgeable.md>
> Thanks!
> 
>> Would you prefer if I did / did not add your name to the proposal? I feel 
>> guilty taking all the credit.
> 
> 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!
> 
>       - Doug
> 

Happy to do so!

Russ

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to