[Accepted] SE-0140: Bridge Optional As Its Payload Or NSNull


(Douglas Gregor) #1

Hello Swift community,

The review of SE-0140 <https://github.com/apple/swift-evolution/blob/master/proposals/0140-bridge-optional-to-nsnull.md> "Bridge Optional As Its Payload Or NSNull” ran from September 2…8, 2016. The proposal is accepted with one modification (described below).

Reviews on this proposal were mixed, with many expressing significant concerns about the ability to place an optional value into an ‘Any’, particularly when the ‘Any’ comes from a nonnull-annotated Objective-C API:

  // Objective-C
  @interface MyClass : NSObject
  - (void)doSomething:(nonnull id)object;
  @end

  // Swift
  let stringOpt: String? = getSomeString()
  MyClass().doSomething(stringOpt) // allowed; likely a programmer error

This behavior was introduced as part of id-as-Any bridging (SE-0116 <https://github.com/apple/swift-evolution/blob/master/proposals/0116-id-as-any.md>). As an amendment to SE-0140, Swift will produce a warning when an optional value is converted to a value of type Any, e.g.,

  MyClass().doSomething(stringOpt) // warning: optional value of type ‘String?’ is converted to an ‘Any’
            // note: use ‘!’ to force-unwrap the optional
            // note: use ‘??’ to provide a default value if the optional is nil
            // note: use ‘as Any’ to silence this warning

Such a warning will address most accidental injections of optional values into Any, and the core team felt that this addresses accidental boxing of optional values better than leaving the opaque object types to fail fast in Objective-C code that inspects them (e.g., see this message <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160905/026961.html> for a negative review partly on these grounds).

To the main point of this proposal, which is to bridging to either the payload or NSNull, the core team felt that:

1) Bridging to the payload or NSNull brings to Objective-C code the same behavior that is already present in Swift’s type system, where an optional containing a payload can be dynamically casted to its payload type. For example, this is well-formed in Swift:

   let optString: String? = "hello"
   let anyValue: Any = optString
   let stringValue: String = any as! stringValue // downcast succeeds, produces a String

2) While NSNull is not widely used in Cocoa APIs, it is better to enable those APIs to work properly when nil optional values do get bridged than to have an opaque-to-Objective-C boxed type that does not work well with any Objective-C APIs.

Thank you to everyone who participated in the review!

  - Doug


(Greg Parker) #2

Is there a recommended pattern for defining a callee that actually wants to accept anything including optionals with no warning for the caller?

···

On Sep 12, 2016, at 3:39 PM, Douglas Gregor <dgregor@apple.com> wrote:

As an amendment to SE-0140, Swift will produce a warning when an optional value is converted to a value of type Any, e.g.,

  MyClass().doSomething(stringOpt) // warning: optional value of type ‘String?’ is converted to an ‘Any’
            // note: use ‘!’ to force-unwrap the optional
            // note: use ‘??’ to provide a default value if the optional is nil
            // note: use ‘as Any’ to silence this warning

Such a warning will address most accidental injections of optional values into Any, and the core team felt that this addresses accidental boxing of optional values better than leaving the opaque object types to fail fast in Objective-C code that inspects them (e.g., see this message <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160905/026961.html> for a negative review partly on these grounds).

--
Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler


(Jean-Daniel) #3

A function that accept anything (including nil) shouldn’t be declared as nonnull. If I understand correctly, it should be enough to avoid warning.

···

Le 13 sept. 2016 à 01:48, Greg Parker via swift-evolution <swift-evolution@swift.org> a écrit :

On Sep 12, 2016, at 3:39 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

As an amendment to SE-0140, Swift will produce a warning when an optional value is converted to a value of type Any, e.g.,

  MyClass().doSomething(stringOpt) // warning: optional value of type ‘String?’ is converted to an ‘Any’
            // note: use ‘!’ to force-unwrap the optional
            // note: use ‘??’ to provide a default value if the optional is nil
            // note: use ‘as Any’ to silence this warning

Such a warning will address most accidental injections of optional values into Any, and the core team felt that this addresses accidental boxing of optional values better than leaving the opaque object types to fail fast in Objective-C code that inspects them (e.g., see this message <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160905/026961.html> for a negative review partly on these grounds).

Is there a recommended pattern for defining a callee that actually wants to accept anything including optionals with no warning for the caller?


(Douglas Gregor) #4

One could write it as a generic function:

  func identity<T>(_ value: T) -> T { … }

  - Doug

···

On Sep 12, 2016, at 4:48 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

On Sep 12, 2016, at 3:39 PM, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> wrote:

As an amendment to SE-0140, Swift will produce a warning when an optional value is converted to a value of type Any, e.g.,

  MyClass().doSomething(stringOpt) // warning: optional value of type ‘String?’ is converted to an ‘Any’
            // note: use ‘!’ to force-unwrap the optional
            // note: use ‘??’ to provide a default value if the optional is nil
            // note: use ‘as Any’ to silence this warning

Such a warning will address most accidental injections of optional values into Any, and the core team felt that this addresses accidental boxing of optional values better than leaving the opaque object types to fail fast in Objective-C code that inspects them (e.g., see this message <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160905/026961.html> for a negative review partly on these grounds).

Is there a recommended pattern for defining a callee that actually wants to accept anything including optionals with no warning for the caller?


(Kenny Leung) #5

Maybe that could be:

func funkyFunc(getDown :Any?)

-Kenny

···

On Sep 12, 2016, at 4:48 PM, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:

On Sep 12, 2016, at 3:39 PM, Douglas Gregor <dgregor@apple.com> wrote:

As an amendment to SE-0140, Swift will produce a warning when an optional value is converted to a value of type Any, e.g.,

  MyClass().doSomething(stringOpt) // warning: optional value of type ‘String?’ is converted to an ‘Any’
            // note: use ‘!’ to force-unwrap the optional
            // note: use ‘??’ to provide a default value if the optional is nil
            // note: use ‘as Any’ to silence this warning

Such a warning will address most accidental injections of optional values into Any, and the core team felt that this addresses accidental boxing of optional values better than leaving the opaque object types to fail fast in Objective-C code that inspects them (e.g., see this message for a negative review partly on these grounds).

Is there a recommended pattern for defining a callee that actually wants to accept anything including optionals with no warning for the caller?

--
Greg Parker gparker@apple.com Runtime Wrangler

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