> On Mar 23, 2016, at 1:25 PM, Russ Bishop <[email protected]> wrote:
>
>
>> On Mar 23, 2016, at 11:49 AM, Douglas Gregor <[email protected]
>> <mailto:[email protected]>> wrote:
>>>
>>> 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?
I realize that my comment about factory initializers was a bit off: these are
initializers on the value type, so there are no “class clusters” to be had.
Sorry for the noise!
> 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 :)]
The problem I have with allowing the ambiguity is that you can get weird
behavior if Bar and Foo are in different modules: import just Bar’s module, and
an Objective-C API mentioning SomeObjectiveCType gets bridged as a Bar. Import
just Foo’s module, and an Objective-C API mentioning SomeObjectiveCType gets
bridged as a Foo. Import both, and SomeObjectiveCType doesn’t get bridged! Now
start splitting class hierarchies among those modules and you get some very
inconsistent imports… that’s why I think this needs to be an error.
>
>
> `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.
It’s hardcoded, but it’s completely reasonable to imagine swift_bridge doing
this some day.
> 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 would be hard for me to get motivated for such a proposal; at that point,
just wrap up the API.
> 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.
I don’t have a good answer here; today, it’s hardcoded.
> 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.
Yes, that’s a reasonable approach. I don’t think it’s important for this
proposal.
Two last comments came up, then I’d like to merge and schedule this:
(1) isBridgedToObjectiveC should be a computed property, not a function
(2) Please add something indicating that, while one can “as” cast between a
value type and its bridged Objective-C type, there are no implicit conversions.
We currently have implicit conversions from String -> NSString, Array<T> ->
NSArray, Dictionary<K, V> -> NSDictionary, and Set<T> -> NSSet, but we’re not
happy about them and we don’t want to create more implicit conversions [*].
- Doug
[*] The fact that you mourn the loss of @conversion did not go unnoticed as I
was writing this ;)
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution