First of all, I'm really happy with this proposal so far. I really appreciate 
the work that's been done to improve Swift and Objective-C interoperability.

Now, question: Does this proposal also improve bridging from Objective-C to 
Swift or only the other direction? For example, let's say an `[Any]` contains 
either `Foo` or `NSNull`. Could this bridge to Swift as `[Foo?]`? I'd like to 
be able to write

let x = [Foo(), Foo(), nil] as [Foo?] as [Any]
let x2 = x as! [Foo?] // Already works

let y = [Foo(), Foo(), NSNull()] as [Any]
let y2 = y as! [Foo?] // Should work

and have this succeed. That is, an `[Any]` can be cast to `[T?]` either if it 
only contains `T` and `NSNull` or if it only contains `T?`, not some 
combination of both.

> On Aug 24, 2016, at 11:20 AM, Douglas Gregor via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 
>> On Aug 24, 2016, at 4:16 AM, David Rönnqvist <david.ronnqv...@gmail.com 
>> <mailto:david.ronnqv...@gmail.com>> wrote:
>> 
>> I have some problems understanding the scope of this proposal. More 
>> specifically if it’s limited to arrays and dictionaries or if it’s broader 
>> than that, and if it’s limited to objects that originate in Swift or if the 
>> same applies for objects that originate in Objective-C code.
> 
> It’s broader than that. It affects any Optional value that is put into an 
> ‘Any’ and passed to Objective-C. Note, however, that if you have a nullable 
> parameter in Objective-C, e.g.,
> 
>       -(void)methodWithObject:(nullable id)object;
> 
> Which comes into Swift as
> 
>       func method(with object: Any?)
> 
> Then ‘nil’ will be passed through as ‘nil’. This only affects the case where 
> you’re passing a Swift optional to a non-optional parameter:
> 
>       -(void)methodWithNonNullObject:(nonnull id)object;
> 
>       func method(withNonNullObject object: Any)
> 
>> 
>> For me, it makes sense that Swift arrays of type [C?] and [Any] would bridge 
>> to Objective-C as NSArrays bridge nils to NSNull. That feels like the most 
>> natural way of representing those missing values in Objective-C. 
> 
> Right. The alternative is that nil values bridge to an opaque box type known 
> only to the Swift runtime. NSNull seems strictly better here, because 
> Objective-C code can reason about it.
> 
>> For dictionaries of type [K:C?] and [K:Any] I feel that bridging Swift nils 
>> to NSNull is pretty straight forward and allows for the distinction of a key 
>> with no value and a key with an explicit nil value. However, I feel that the 
>> same doesn’t work in the other direction. If a NSNull value in an 
>> Objective-C NSDictionary would bridge to a nil value it wouldn’t be possible 
>> to distinguish between a key without a value and key with a nil value 
>> (something one might have to do when checking the KVO change dictionary).  
> 
> NSNulls are handled dynamically. If you wanted to check whether Objective-C 
> put an ‘NSNull’ in there explicitly, you can do so with “as? NSNull”.  If 
> instead you do “as? SomeType?”, the NSNull will become the ‘nil’ value in the 
> SomeType.
> 
>> 
>> There are also some APIs that make a distinction between NSNull and nil, for 
>> example action(for:forKey:) on CALayerDelegate. Does this proposal have any 
>> impact on those APIs?
> 
> That method returns “CAAction?”, so ‘nil’ will come through as ‘nil’ and 
> NSNull can be stored in the .some(x).
> 
>       - Doug
> 
>> 
>> - David
>> 
>>> On 24 Aug 2016, at 00:36, Douglas Gregor via swift-evolution 
>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>> 
>>> Introduction
>>> 
>>> Optionals can be used as values of the type Any, but only bridge as opaque 
>>> objects in Objective-C. We should bridge Optionals with some value by 
>>> bridging the wrapped value, and bridge nils to the NSNull singleton.
>>> 
>>> Swift-evolution thread: TBD 
>>> <https://lists.swift.org/pipermail/swift-evolution/>
>>>  
>>> <https://github.com/jckarter/swift-evolution/blob/be49e08f56450ffea394306198bcd25f58915e30/proposals/XXXX-bridge-optional-to-nsnull.md#motivation>Motivation
>>> 
>>> SE-0116 
>>> <https://github.com/apple/swift-evolution/blob/master/proposals/0116-id-as-any.md>
>>>  changed how Objective-C's id and untyped collections import into Swift to 
>>> use the Any type. This makes it much more natural to pass in Swift value 
>>> types such as String and Array, but introduces the opportunity for 
>>> optionality mismatches, since an Any can contain a wrapped Optional value 
>>> just like anything else. Our current behavior, where Optional is given only 
>>> the default opaque bridging behavior, leads to brittle transitivity 
>>> problems with collection subtyping. For example, an array of Optional 
>>> objects bridges to an NSArray of opaque objects, unusable from ObjC:
>>> 
>>> class C {}
>>> let objects: [C?] = [C(), nil, C()]
>>> The more idiomatic mapping would be to use NSNull or some other sentinel to 
>>> represent the missing values (since NSArray cannot directly store nil). 
>>> Counterintuitively, this is in fact what you get if you bridge an array of 
>>> Any with nil elements:
>>> 
>>> class C {}
>>> let objects: [Any] = [C(), nil as C?, C()]
>>> though with an opaque box taking the place of the standard NSNull sentinel. 
>>> Since there's a subtype relationship between T and Optional<T>, it's also 
>>> intuitive to expect that the bridging operation be consistent between T and 
>>> occupied values of Optional<T>.
>>> 
>>>  
>>> <https://github.com/jckarter/swift-evolution/blob/be49e08f56450ffea394306198bcd25f58915e30/proposals/XXXX-bridge-optional-to-nsnull.md#proposed-solution>Proposed
>>>  solution
>>> 
>>> When an Optional<T> value is bridged to an Objective-C object, if it 
>>> contains some value, that value should be bridged; otherwise, NSNull or 
>>> another sentinel object should be used.
>>> 
>>>  
>>> <https://github.com/jckarter/swift-evolution/blob/be49e08f56450ffea394306198bcd25f58915e30/proposals/XXXX-bridge-optional-to-nsnull.md#detailed-design>Detailed
>>>  design
>>> 
>>> some maps to the bridged value
>>> none maps to NSNull
>>> if we don't want to lose information about nested optionals, we'd need a 
>>> unique SwiftNull object for every optional type, so that .some(.none) maps 
>>> to NSNull and .none maps to SwiftNull(T?)
>>>  
>>> <https://github.com/jckarter/swift-evolution/blob/be49e08f56450ffea394306198bcd25f58915e30/proposals/XXXX-bridge-optional-to-nsnull.md#impact-on-existing-code>Impact
>>>  on existing code
>>> 
>>> This change has no static source impact, but changes the dynamic behavior 
>>> of the Objective-C bridge. From Objective-C's perspective, Optionals that 
>>> used to bridge as opaque objects will now come in as semantically 
>>> meaningful Objective-C objects. This should be a safe change, since 
>>> existing code should not be relying on the behavior of opaque bridged 
>>> objects. From Swift's perspective, values should still be able to 
>>> round-trip from Optional to Any to id to Anyand back by dynamic casting.
>>> 
>>>  
>>> <https://github.com/jckarter/swift-evolution/blob/be49e08f56450ffea394306198bcd25f58915e30/proposals/XXXX-bridge-optional-to-nsnull.md#alternatives-considered>Alternatives
>>>  considered
>>> 
>>> Do nothing
>>> Attempt to trap or error when Optionals are used as Anys -- would be good 
>>> QoI to warn, but it can't be prevented, and is occasionally desired
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution 
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

Reply via email to