[Draft] Abolish IUO type


(Chris Willmore) #1

Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

Proposal: SE-NNNN
Author: Chris Willmore <http://github.com/cwillmor>
Status: TBD
Review Manager: TBD
This proposal seeks to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations. Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it (or, in the case of a function, the return value of its application) may be implicitly unwrapped.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#motivation>Motivation

The ImplicitlyUnwrappedOptional ("IUO") type is a valuable tool for importing Objective-C APIs where the nullability of a parameter or return type is unspecified. It also represents a convenient mechanism for working through definite initialization problems in initializers. However, IUOs are a transitional technology; they represent an easy way to work around un-annotated APIs, or the lack of language features that could more elegantly handle certain patterns of code. As such, we would like to limit their usage moving forward, and introduce more specific language features to take their place. Except for a few specific scenarios, optionals are always the safer bet, and we’d like to encourage people to use them instead of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are actually required, and put the Swift language on the path to removing implicitly unwrapped optionals from the system entirely when other technologies render them unnecessary. It also completely abolishes any notion of IUOs below the type-checker level of the compiler, which will substantially simplify the compiler implementation.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed solution

I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations
Declarations that are marked with the IUO attribute must have optional type. A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

A variable with the IUO attribute may still be converted to a value with non-optional type, through either evaluating it in a context which requires the non-optional type, explicitly converting it to a non-optional type using the as operator, binding it to a variable with explicit optional type, or using the force operator (!).

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)
let x3: Int! = f() // succeeds; x3: Int? = .Some(3), has IUO attribute
let x4: Int = f() // succeeds; x4: Int = 3
let a1 = [f()] // succeeds; a: [Int?] = [.Some(3)]
let a2: [Int!] = [f()] // illegal, nested IUO type
let a3: [Int] = [f()] // succeeds; a: [Int] = [3]

func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute
let y1 = g() // succeeds; y1: Int? = .None
let y2: Int? = g() // succeeds; y2: Int? = .None
let y3: Int! = g() // succeeds; y3: Int? = .None, has IUO attribute
let y4: Int = g() // traps
let b1 = [g()] // succeeds; b: [Int?] = [.None]
let b2: [Int!] = [g()] // illegal, nested IUO type
let b3: [Int] = [g()] // traps

func p<T>(x: T) { print(x) }
p(f()) // prints "Optional(3)"; p is instantiated with T = Int?

if let x5 = f() {
  // executes, with x4: Int = 3
}
if let y5 = g() {
  // does not execute
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact on existing code

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Explicitly written nested IUO types (like [Int!]) will have to be rewritten to use the corresponding optional type ([Int?]) or non-optional type ([Int]) depending on what's more appropriate for the context. However, most declarations with non-nested IUO type will continue to work as they did before.

It will still be possible to declare IUO properties, so the following deferred initialization pattern will still be possible:

struct S {
  var x: Int!
  init() {}
  func initLater(x someX: Int) { x = someX }
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#future-directions>Future directions

Because this proposal changes the IUO-ness of a declaration from being part of its type to being an attribute of the declaration, it might make sense to changes the syntactic representation of the attribute to match, e.g. by creating a new @implicitly_unwrapped attribute on declarations:

let x3: Int! = f() // !-based syntax
@implicitly_unwrapped let x3: Int? = f() // attribute-based syntax


(Chris Lattner) #2

Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

You already know this, but I am +100 on this proposal. We definitely need to “nerf” IUO, to get to a more predictable and robust model.

Some minor comments on the writing below. The most significant one is that I think that describing this in terms of an IUO attribute (which is an internal implementation detail) makes the proposal more confusing than necessary for the non-compiler hackers. :-)

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed solution
I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations

+ Function decls includes the result type as well as the parameter decls, but not a varargs element type.
+ Subscripts.

Declarations that are marked with the IUO attribute must have optional type.

Is the IUO attribute actually user exposed in any way, or is it an internal compiler detail? I would expect us to continue to use and prefer (e.g. in the ASTPrinter) the T! syntax.

A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

For clarity in the wording, I’d suggest something along the lines of:

"A reference to a variable or property with the IUO attribute prefers to bind to an optional, but may also be implicitly forced …”

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

This again is talking about the compiler implementation details.

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

I think that this statement will draw confusion in review, because “x” has IUO behavior. Perhaps you can talk about it in terms of type propagation and describe the behavior along the lines of:

if the expression can be successfully type checked with the declaration producing a strong optional, it does. However, the type checker will fall back to trying to fall back to forcing the optional - if that succeeds it will. The end result of this is that the result of any rvalue that refers to something declared as an IUO will either have T or T? type. This means that in:

let x: Int! = 5
let y = x
let z = x+0

“x” is declared as an IUO, but because the initializer for y type checks correctly as an optional, y will be bound as type "Int?”. Since the initializer for z does not type check with x declared as an optional, the compiler forces the IUO and type checks the initializer as an Int.

This model is more predictable, because IUOs are forced much more locally to where they are introduced into code, they do not propagate unpredictably through code. Any unpredictable propagation of an unknownable-null value is instead propagates as a strong optional, which is the safe default.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)

.some and .none are lower case these days :-)

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact on existing code

I would add an intro paragraph/sentence saying that we do expect this to be a source breaking change, and thus it makes sense to do in Swift 3. We consider this to be acceptable because IUOs coming in through imported ObjC/C modules naturally “shimmer” in IUO’ness as nullability gets audited.

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Overall, looks great, thank you for writing this up!

-Chris

···

On Mar 15, 2016, at 10:03 PM, Chris Willmore via swift-evolution <swift-evolution@swift.org> wrote:


(Mark Anders) #3

It seems reasonable. If I understand it correctly, I would still be able to write code like this:

@IBOutlet weak var emailTextField: UITextField\!

I don’t have any issues with the limitations as proposed.

Btw, I included the above line because with all of the examples you used, IMO, it can be easy to question how important IUO are. I’ve never needed [Int!], for example or relied on the compiler inferring that something is implicitly unwrapped.

However I have a ton of code like the line above, and it would be a drag if these all became optionals. I wouldn’t want to have to if let or guard let for every property in every function where they are used.

In general where I find myself using them the most is in situations where the initialization patterns don’t apply. Another example is in unit tests where you want to tear down and rebuild but not necessarily re-construct. These might fall in to the category of where you might “introduce more specific language features to take their place”, but since there’s no mention of what those might be, it’s hard to know what one is getting to replace what one’s giving up.

Finally, I really don’t like @implicitly_unwrapped.

@IBOutlet @implicitly\_unwrapped weak var emailTextField: UITextField?
@IBOutlet @implicitly\_unwrapped weak var passwordTextField: UITextField?
@IBOutlet @implicitly\_unwrapped weak var loginButton: UIButton?

Making things really ugly isn’t going to discourage me from using them in situations like this and I think it makes me more aware of the danger involved. It just makes it harder to read, IMO.

Mark

···

On March 15, 2016 at 10:03:24 PM, Chris Willmore via swift-evolution (swift-evolution@swift.org) wrote:

Hi, swift-evolution,

Some colleagues and I have been working on a proposal to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

Proposal: SE-NNNN
Author: Chris Willmore
Status: TBD
Review Manager: TBD
This proposal seeks to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations. Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it (or, in the case of a function, the return value of its application) may be implicitly unwrapped.

Motivation

The ImplicitlyUnwrappedOptional ("IUO") type is a valuable tool for importing Objective-C APIs where the nullability of a parameter or return type is unspecified. It also represents a convenient mechanism for working through definite initialization problems in initializers. However, IUOs are a transitional technology; they represent an easy way to work around un-annotated APIs, or the lack of language features that could more elegantly handle certain patterns of code. As such, we would like to limit their usage moving forward, and introduce more specific language features to take their place. Except for a few specific scenarios, optionals are always the safer bet, and we’d like to encourage people to use them instead of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are actually required, and put the Swift language on the path to removing implicitly unwrapped optionals from the system entirely when other technologies render them unnecessary. It also completely abolishes any notion of IUOs below the type-checker level of the compiler, which will substantially simplify the compiler implementation.

Proposed solution

I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations
Declarations that are marked with the IUO attribute must have optional type. A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

A variable with the IUO attribute may still be converted to a value with non-optional type, through either evaluating it in a context which requires the non-optional type, explicitly converting it to a non-optional type using the as operator, binding it to a variable with explicit optional type, or using the force operator (!).

Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)
let x3: Int! = f() // succeeds; x3: Int? = .Some(3), has IUO attribute
let x4: Int = f() // succeeds; x4: Int = 3
let a1 = [f()] // succeeds; a: [Int?] = [.Some(3)]
let a2: [Int!] = [f()] // illegal, nested IUO type
let a3: [Int] = [f()] // succeeds; a: [Int] = [3]

func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute
let y1 = g() // succeeds; y1: Int? = .None
let y2: Int? = g() // succeeds; y2: Int? = .None
let y3: Int! = g() // succeeds; y3: Int? = .None, has IUO attribute
let y4: Int = g() // traps
let b1 = [g()] // succeeds; b: [Int?] = [.None]
let b2: [Int!] = [g()] // illegal, nested IUO type
let b3: [Int] = [g()] // traps

func p<T>(x: T) { print(x) }
p(f()) // prints "Optional(3)"; p is instantiated with T = Int?

if let x5 = f() {
  // executes, with x4: Int = 3
}
if let y5 = g() {
  // does not execute
}
Impact on existing code

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Explicitly written nested IUO types (like [Int!]) will have to be rewritten to use the corresponding optional type ([Int?]) or non-optional type ([Int]) depending on what's more appropriate for the context. However, most declarations with non-nested IUO type will continue to work as they did before.

It will still be possible to declare IUO properties, so the following deferred initialization pattern will still be possible:

struct S {
  var x: Int!
  init() {}
  func initLater(x someX: Int) { x = someX }
}
Future directions

Because this proposal changes the IUO-ness of a declaration from being part of its type to being an attribute of the declaration, it might make sense to changes the syntactic representation of the attribute to match, e.g. by creating a new @implicitly_unwrapped attribute on declarations:

let x3: Int! = f() // !-based syntax
@implicitly_unwrapped let x3: Int? = f() // attribute-based syntax

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


(Russ Bishop) #4

Let me play devil’s advocate: why not just get rid of implicit unwrapping entirely?

Apple’s Objective-C APIs have had plenty of time to be audited by now. Anything not annotated can be assumed to be optional (which is the safest bet).

The only case where IUOs are necessary is when you can’t cram something into the Swift initialization patterns (view controllers with outlets are the primary example). Having an attribute to suppress the compiler errors about failing to initialize outlet properties solves that problem (and any similar initialization problem) while limiting the scope. For example:
  
  @noinit @IBOutlet var view: UIView

I’ve gotten into the habit of treating `!` as if it were `?` anyway and it hasn’t steered me wrong yet.

Russ

···

On Mar 15, 2016, at 10:03 PM, Chris Willmore via swift-evolution <swift-evolution@swift.org> wrote:

Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

Proposal: SE-NNNN
Author: Chris Willmore <http://github.com/cwillmor>
Status: TBD
Review Manager: TBD
This proposal seeks to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations. Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it (or, in the case of a function, the return value of its application) may be implicitly unwrapped.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#motivation>Motivation


(James Campbell) #5

One thing I've had bit me is the lack of some sort of confirmation, see
this example.

I have a objective-c method in a library like so:

- (void)observe:(CallbackBlock)block;

The CallbackBlock is a type def-ed block like so:

typedef void (^CallbackBlock)(FDataSnapshot *snapshot);

The parameter in the block gets converted into a IUO, I ended up releasing
an app that crashed due to that IUO being nil.

The code that crashed was something like this

object.observe {
$0.doSomething()
}

There is no way to tell that the $0 was a IUO. The compiler didn't force me
to confirm in it in some way using a ! and unless I remembered to check the
header I would have a crash.

How would this work under your proposal ?

···

*___________________________________*

*James⎥Head Of CEO*

*james@supmenow.com <james@supmenow.com>⎥supmenow.com <http://supmenow.com>*

*Sup*

*Runway East *

*10 Finsbury Square*

*London*

* EC2A 1AF *

On Wed, Mar 16, 2016 at 5:03 AM, Chris Willmore via swift-evolution < swift-evolution@swift.org> wrote:

Hi, swift-evolution,

Some colleagues and I have been working on a proposal
<https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to
remove the ImplicitlyUnwrappedOptional type from Swift and replace it with
an IUO decl attribute. Please have a look; I would greatly appreciate any
comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

   - Proposal: SE-NNNN
   - Author: Chris Willmore <http://github.com/cwillmor>
   - Status: TBD
   - Review Manager: TBD

This proposal seeks to remove the ImplicitlyUnwrappedOptional type from
the Swift type system and replace it with an IUO attribute on declarations.
Appending ! to the type of a Swift declaration will give it optional type
and annotate the declaration with an attribute stating that it (or, in the
case of a function, the return value of its application) may be implicitly
unwrapped.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#motivation>
Motivation

The ImplicitlyUnwrappedOptional ("IUO") type is a valuable tool for
importing Objective-C APIs where the nullability of a parameter or return
type is unspecified. It also represents a convenient mechanism for working
through definite initialization problems in initializers. However, IUOs are
a transitional technology; they represent an easy way to work around
un-annotated APIs, or the lack of language features that could more
elegantly handle certain patterns of code. As such, we would like to limit
their usage moving forward, and introduce more specific language features
to take their place. Except for a few specific scenarios, optionals are
always the safer bet, and we’d like to encourage people to use them instead
of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are
actually required, and put the Swift language on the path to removing
implicitly unwrapped optionals from the system entirely when other
technologies render them unnecessary. It also completely abolishes any
notion of IUOs below the type-checker level of the compiler, which will
substantially simplify the compiler implementation.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed
solution

I propose demoting implicitly unwrapped optionals from being a first-class
type in the Swift type system to being an attribute on declarations in
Swift. This attribute will be allowed in the following locations:

   - property and variable declarations
   - initializer declarations
   - function declarations

Declarations that are marked with the IUO attribute must have optional
type. A reference to a variable or property with the IUO attribute may be
implicitly forced (i.e. converted to the underlying type) when being
type-checked, thus replicating the current behavior of a declaration with
IUO type. Likewise, the result of a function application or initialization
where the callee is a reference to a function declaration with the IUO
attribute may be implicitly forced.

The appearance of ! at the end of a property or variable type no longer
indicates that the property or variable has IUO type; rather, it indicates
that (1) the declaration has optional type, and (2) the declaration has the
IUO attribute. The appearance of ! at the end of the return type of a
function indicates that the function has optional return type and the IUO
attribute. The use of init! in an initializer declaration indicates that
the initializer is failable and has the IUO attribute.

Because there is no longer an IUO type, types with nested IUOs are no
longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For
example, in the following code:

let x: Int! = 5
let y = x

… x and y both have type Int?, not Int!, and y lacks the IUO attribute.
This rule prevents IUO attributes from spreading via type inference.

A variable with the IUO attribute may still be converted to a value with
non-optional type, through either evaluating it in a context which requires
the non-optional type, explicitly converting it to a non-optional type
using the as operator, binding it to a variable with explicit optional
type, or using the force operator (!).

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>
Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)
let x3: Int! = f() // succeeds; x3: Int? = .Some(3), has IUO attribute
let x4: Int = f() // succeeds; x4: Int = 3
let a1 = [f()] // succeeds; a: [Int?] = [.Some(3)]
let a2: [Int!] = [f()] // illegal, nested IUO type
let a3: [Int] = [f()] // succeeds; a: [Int] = [3]

func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute
let y1 = g() // succeeds; y1: Int? = .None
let y2: Int? = g() // succeeds; y2: Int? = .None
let y3: Int! = g() // succeeds; y3: Int? = .None, has IUO attribute
let y4: Int = g() // traps
let b1 = [g()] // succeeds; b: [Int?] = [.None]
let b2: [Int!] = [g()] // illegal, nested IUO type
let b3: [Int] = [g()] // traps

func p<T>(x: T) { print(x) }
p(f()) // prints "Optional(3)"; p is instantiated with T = Int?

if let x5 = f() {
  // executes, with x4: Int = 3
}
if let y5 = g() {
  // does not execute
}

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact
on existing code

Variable bindings which previously had inferred type T! from their
binding on the right-hand side will now have type T?. The compiler will
emit an error at sites where those bound variables are used in a context
that demands a non-optional type and suggest that the value be forced with
the ! operator.

Explicitly written nested IUO types (like [Int!]) will have to be
rewritten to use the corresponding optional type ([Int?]) or non-optional
type ([Int]) depending on what's more appropriate for the context.
However, most declarations with non-nested IUO type will continue to work
as they did before.

It will still be possible to declare IUO properties, so the following
deferred initialization pattern will still be possible:

struct S {
  var x: Int!
  init() {}
  func initLater(x someX: Int) { x = someX }
}

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#future-directions>Future
directions

Because this proposal changes the IUO-ness of a declaration from being
part of its type to being an attribute of the declaration, it might make
sense to changes the syntactic representation of the attribute to match,
e.g. by creating a new @implicitly_unwrapped attribute on declarations:

let x3: Int! = f() // !-based syntax
@implicitly_unwrapped let x3: Int? = f() // attribute-based syntax

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


(Brent Royal-Gordon) #6

The most significant one is that I think that describing this in terms of an IUO attribute (which is an internal implementation detail) makes the proposal more confusing than necessary for the non-compiler hackers. :slight_smile:

For what it's worth, I actually find it really helpful to have a way to talk about these kinds of features without sugar. I spent most of this proposal going "So, does that mean `Int!` is now `@implicitly_unwrapped Optional<Int>`?"

It's particularly important in this case because `!` implies `?`; there's a lot of magic going on here. Without a completely unambiguous way to write about this behavior, it's hard to talk about it precisely.

For instance, I have two questions for the proposal's author:

* Would the declaration `Int?!` mean `@implicitly_unwrapped Optional<Int>` or `@implicitly_unwrapped Optional<Optional<Int>>`?

* You say that things like `[Int!]` and `(Int!, Int!)` (`Array<@implicitly_unwrapped Optional<Int>>` and `(@implicitly_unwrapped Optional<Int>, @implicitly_unwrapped Optional<Int>)`) are illegal; are `Int!?` and `Int!!` (`Optional<@implicitly_unwrapped Optional<Int>>` and `@implicitly_unwrapped Optional<@implicitly_unwrapped Optional<Int>>`) illegal as well? (Actually, having written this out explicitly, I'm now fairly confident of the answer: yes, they are illegal.)

These kinds of questions are hard to pose unless we have a language to discuss them in, even if that language is rarely actually used when we write code.

···

--
Brent Royal-Gordon
Architechies


(Brent Royal-Gordon) #7

Let me play devil’s advocate: why not just get rid of implicit unwrapping entirely?

Apple’s Objective-C APIs have had plenty of time to be audited by now.

Two reasons:

1. There are still a number of obscure Apple frameworks which have not been audited.

2. Not all imported code comes from Apple frameworks. In particular, Linux is a whole new world of unaudited—and frankly, probably never-going-to-be-audited in large part—code. Each time Swift moves to a new platform, it will need implicit unwrapping again for a few years while the major libraries get audited. Burning your ships is only a good motivational strategy if you don't need to go anywhere else.

···

--
Brent Royal-Gordon
Architechies


(Chris Willmore) #8

Thanks for the thoughtful response, Chris. Comments inline. I’ve updated the draft linked below to reflect your feedback.

Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

You already know this, but I am +100 on this proposal. We definitely need to “nerf” IUO, to get to a more predictable and robust model.

Some minor comments on the writing below. The most significant one is that I think that describing this in terms of an IUO attribute (which is an internal implementation detail) makes the proposal more confusing than necessary for the non-compiler hackers. :slight_smile:

Well, IUO is no longer a type, so what do we call it? I agree that it’s weird to call it an attribute when there’s no way to spell it explicitly as such, but I’m at a loss for alternatives. Maybe we could just say that such a declaration is implicitly unwrapped (forced? unwrappable? forceable?), or declares an implicitly unwrapped property/function/variable. Anyway, I’ve changed “declaration with the IUO attribute” to “IUO declaration” in all places but the first occurrence in my revision.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed solution
I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations

+ Function decls includes the result type as well as the parameter decls, but not a varargs element type.
+ Subscripts.

Good call, added. I added “parameter declarations” as a line item rather than qualify the function-declarations line (and repeat the qualification for initializers, methods, subscripts).

Declarations that are marked with the IUO attribute must have optional type.

Is the IUO attribute actually user exposed in any way, or is it an internal compiler detail? I would expect us to continue to use and prefer (e.g. in the ASTPrinter) the T! syntax.

Re the comment above, should this be rewritten as “Implicitly unwrapped declarations must have optional type”?

A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

For clarity in the wording, I’d suggest something along the lines of:

"A reference to a variable or property with the IUO attribute prefers to bind to an optional, but may also be implicitly forced …”

Yep, makes sense; added.

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

This again is talking about the compiler implementation details.

Possible resolution: “… (2) the declaration may be implicitly unwrapped”? Likewise “… the return value of the function may be implicitly unwrapped".

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

I think that this statement will draw confusion in review, because “x” has IUO behavior. Perhaps you can talk about it in terms of type propagation and describe the behavior along the lines of:

if the expression can be successfully type checked with the declaration producing a strong optional, it does. However, the type checker will fall back to trying to fall back to forcing the optional - if that succeeds it will. The end result of this is that the result of any rvalue that refers to something declared as an IUO will either have T or T? type. This means that in:

let x: Int! = 5
let y = x
let z = x+0

“x” is declared as an IUO, but because the initializer for y type checks correctly as an optional, y will be bound as type "Int?”. Since the initializer for z does not type check with x declared as an optional, the compiler forces the IUO and type checks the initializer as an Int.

This model is more predictable, because IUOs are forced much more locally to where they are introduced into code, they do not propagate unpredictably through code. Any unpredictable propagation of an unknownable-null value is instead propagates as a strong optional, which is the safe default.

Thanks for the detailed feedback here. I’ve rewritten this section.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)

.some and .none are lower case these days :slight_smile:

So they are! Fixed.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact on existing code

I would add an intro paragraph/sentence saying that we do expect this to be a source breaking change, and thus it makes sense to do in Swift 3. We consider this to be acceptable because IUOs coming in through imported ObjC/C modules naturally “shimmer” in IUO’ness as nullability gets audited.

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Overall, looks great, thank you for writing this up!

Thank you!
— Chris W.

···

On Mar 16, 2016, at 5:01 PM, Chris Lattner <clattner@apple.com> wrote:
On Mar 15, 2016, at 10:03 PM, Chris Willmore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Chris Willmore) #9

It seems reasonable. If I understand it correctly, I would still be able to write code like this:

    @IBOutlet weak var emailTextField: UITextField!

That’s correct (and IBOutlets remain a compelling use case for IUOs until we have a better story for deferred initialization).

I don’t have any issues with the limitations as proposed.

Btw, I included the above line because with all of the examples you used, IMO, it can be easy to question how important IUO are. I’ve never needed [Int!], for example or relied on the compiler inferring that something is implicitly unwrapped.

However I have a ton of code like the line above, and it would be a drag if these all became optionals. I wouldn’t want to have to if let or guard let for every property in every function where they are used.

To run with the example above, emailTextField would have type UITextField? but, because it’s an IUO declaration, it would still be usable in contexts that required non-optional UITextField. What would change is that if you were to say, e.g.

let textField = controller.emailTextField

then textField would have type UITextField?. But you could still say

formView.addSubview(controller.emailTextField)

without having to force emailTextField. The type checker recognizes that emailTextField is an IUO property and allows it to be implicitly forced to satisfy the non-optional parameter type UIView of UIView.addSubview.

In general where I find myself using them the most is in situations where the initialization patterns don’t apply. Another example is in unit tests where you want to tear down and rebuild but not necessarily re-construct. These might fall in to the category of where you might “introduce more specific language features to take their place”, but since there’s no mention of what those might be, it’s hard to know what one is getting to replace what one’s giving up.

Finally, I really don’t like @implicitly_unwrapped.

    @IBOutlet @implicitly_unwrapped weak var emailTextField: UITextField?
    @IBOutlet @implicitly_unwrapped weak var passwordTextField: UITextField?
    @IBOutlet @implicitly_unwrapped weak var loginButton: UIButton?

Making things really ugly isn’t going to discourage me from using them in situations like this and I think it makes me more aware of the danger involved. It just makes it harder to read, IMO.

Sorry, I should have made it clear that I’m not suggesting it be spelled @implicitly_unwrapped; you’re right that it’s ugly. I was more suggesting that maybe in the future it should be syntactically similar to other decl attributes. But that’s out of scope for this proposal.

Thanks for the feedback!
— Chris Willmore

···

On Mar 16, 2016, at 5:27 PM, Mark Anders <mark@markanders.net> wrote:

Mark

On March 15, 2016 at 10:03:24 PM, Chris Willmore via swift-evolution (swift-evolution@swift.org <mailto:swift-evolution@swift.org>) wrote:

Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

Proposal: SE-NNNN
Author: Chris Willmore <http://github.com/cwillmor>
Status: TBD
Review Manager: TBD
This proposal seeks to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations. Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it (or, in the case of a function, the return value of its application) may be implicitly unwrapped.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#motivation>Motivation

The ImplicitlyUnwrappedOptional ("IUO") type is a valuable tool for importing Objective-C APIs where the nullability of a parameter or return type is unspecified. It also represents a convenient mechanism for working through definite initialization problems in initializers. However, IUOs are a transitional technology; they represent an easy way to work around un-annotated APIs, or the lack of language features that could more elegantly handle certain patterns of code. As such, we would like to limit their usage moving forward, and introduce more specific language features to take their place. Except for a few specific scenarios, optionals are always the safer bet, and we’d like to encourage people to use them instead of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are actually required, and put the Swift language on the path to removing implicitly unwrapped optionals from the system entirely when other technologies render them unnecessary. It also completely abolishes any notion of IUOs below the type-checker level of the compiler, which will substantially simplify the compiler implementation.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed solution

I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations
Declarations that are marked with the IUO attribute must have optional type. A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

A variable with the IUO attribute may still be converted to a value with non-optional type, through either evaluating it in a context which requires the non-optional type, explicitly converting it to a non-optional type using the as operator, binding it to a variable with explicit optional type, or using the force operator (!).

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)
let x3: Int! = f() // succeeds; x3: Int? = .Some(3), has IUO attribute
let x4: Int = f() // succeeds; x4: Int = 3
let a1 = [f()] // succeeds; a: [Int?] = [.Some(3)]
let a2: [Int!] = [f()] // illegal, nested IUO type
let a3: [Int] = [f()] // succeeds; a: [Int] = [3]

func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute
let y1 = g() // succeeds; y1: Int? = .None
let y2: Int? = g() // succeeds; y2: Int? = .None
let y3: Int! = g() // succeeds; y3: Int? = .None, has IUO attribute
let y4: Int = g() // traps
let b1 = [g()] // succeeds; b: [Int?] = [.None]
let b2: [Int!] = [g()] // illegal, nested IUO type
let b3: [Int] = [g()] // traps

func p<T>(x: T) { print(x) }
p(f()) // prints "Optional(3)"; p is instantiated with T = Int?

if let x5 = f() {
  // executes, with x4: Int = 3
}
if let y5 = g() {
  // does not execute
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact on existing code

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Explicitly written nested IUO types (like [Int!]) will have to be rewritten to use the corresponding optional type ([Int?]) or non-optional type ([Int]) depending on what's more appropriate for the context. However, most declarations with non-nested IUO type will continue to work as they did before.

It will still be possible to declare IUO properties, so the following deferred initialization pattern will still be possible:

struct S {
  var x: Int!
  init() {}
  func initLater(x someX: Int) { x = someX }
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#future-directions>Future directions

Because this proposal changes the IUO-ness of a declaration from being part of its type to being an attribute of the declaration, it might make sense to changes the syntactic representation of the attribute to match, e.g. by creating a new @implicitly_unwrapped attribute on declarations:

let x3: Int! = f() // !-based syntax
@implicitly_unwrapped let x3: Int? = f() // attribute-based syntax

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


(Chris Willmore) #10

One thing I've had bit me is the lack of some sort of confirmation, see this example.

I have a objective-c method in a library like so:

- (void)observe:(CallbackBlock)block;

The CallbackBlock is a type def-ed block like so:

typedef void (^CallbackBlock)(FDataSnapshot *snapshot);

The parameter in the block gets converted into a IUO, I ended up releasing an app that crashed due to that IUO being nil.

The code that crashed was something like this

object.observe {
$0.doSomething()
}

There is no way to tell that the $0 was a IUO. The compiler didn't force me to confirm in it in some way using a ! and unless I remembered to check the header I would have a crash.

How would this work under your proposal ?

This is a great question. I think it would make the most sense to import the CallbackBlock type as (FDataSnapshot?) -> (), since there’s no decl to hang the IUO attribute onto. Then $0 ends up with type FDataSnapshot? (i.e. Optional<FDataSnapshot>), and the compiler would not allow you to simply call doSomething() on $0 without forcing it first.
— Chris Willmore

···

On Mar 18, 2016, at 4:20 AM, James Campbell <james@supmenow.com> wrote:

___________________________________

James⎥Head Of CEO

james@supmenow.com <mailto:james@supmenow.com>⎥supmenow.com <http://supmenow.com/>
Sup

Runway East >

10 Finsbury Square

London

> EC2A 1AF

On Wed, Mar 16, 2016 at 5:03 AM, Chris Willmore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hi, swift-evolution,

Some colleagues and I have been working on a proposal <https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md> to remove the ImplicitlyUnwrappedOptional type from Swift and replace it with an IUO decl attribute. Please have a look; I would greatly appreciate any comments you have before I push this proposal forward.

https://github.com/cwillmor/swift-evolution/blob/master/proposals/0000-abolish-iuo.md

Thanks,
— Chris Willmore

Abolish ImplicitlyUnwrappedOptional type

Proposal: SE-NNNN
Author: Chris Willmore <http://github.com/cwillmor>
Status: TBD
Review Manager: TBD
This proposal seeks to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations. Appending ! to the type of a Swift declaration will give it optional type and annotate the declaration with an attribute stating that it (or, in the case of a function, the return value of its application) may be implicitly unwrapped.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#motivation>Motivation

The ImplicitlyUnwrappedOptional ("IUO") type is a valuable tool for importing Objective-C APIs where the nullability of a parameter or return type is unspecified. It also represents a convenient mechanism for working through definite initialization problems in initializers. However, IUOs are a transitional technology; they represent an easy way to work around un-annotated APIs, or the lack of language features that could more elegantly handle certain patterns of code. As such, we would like to limit their usage moving forward, and introduce more specific language features to take their place. Except for a few specific scenarios, optionals are always the safer bet, and we’d like to encourage people to use them instead of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are actually required, and put the Swift language on the path to removing implicitly unwrapped optionals from the system entirely when other technologies render them unnecessary. It also completely abolishes any notion of IUOs below the type-checker level of the compiler, which will substantially simplify the compiler implementation.

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#proposed-solution>Proposed solution

I propose demoting implicitly unwrapped optionals from being a first-class type in the Swift type system to being an attribute on declarations in Swift. This attribute will be allowed in the following locations:

property and variable declarations
initializer declarations
function declarations
Declarations that are marked with the IUO attribute must have optional type. A reference to a variable or property with the IUO attribute may be implicitly forced (i.e. converted to the underlying type) when being type-checked, thus replicating the current behavior of a declaration with IUO type. Likewise, the result of a function application or initialization where the callee is a reference to a function declaration with the IUO attribute may be implicitly forced.

The appearance of ! at the end of a property or variable type no longer indicates that the property or variable has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has the IUO attribute. The appearance of ! at the end of the return type of a function indicates that the function has optional return type and the IUO attribute. The use of init! in an initializer declaration indicates that the initializer is failable and has the IUO attribute.

Because there is no longer an IUO type, types with nested IUOs are no longer allowed. This includes types such as [Int!] and (Int!, Int!).

The IUO attribute is not inferred from one declaration to another. For example, in the following code:

let x: Int! = 5
let y = x
… x and y both have type Int?, not Int!, and y lacks the IUO attribute. This rule prevents IUO attributes from spreading via type inference.

A variable with the IUO attribute may still be converted to a value with non-optional type, through either evaluating it in a context which requires the non-optional type, explicitly converting it to a non-optional type using the as operator, binding it to a variable with explicit optional type, or using the force operator (!).

<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#examples>Examples

func f() -> Int! { return 3 } // f: () -> Int?, has IUO attribute
let x1 = f() // succeeds; x1: Int? == 3
let x2: Int? = f() // succeeds; x2: Int? = .Some(3)
let x3: Int! = f() // succeeds; x3: Int? = .Some(3), has IUO attribute
let x4: Int = f() // succeeds; x4: Int = 3
let a1 = [f()] // succeeds; a: [Int?] = [.Some(3)]
let a2: [Int!] = [f()] // illegal, nested IUO type
let a3: [Int] = [f()] // succeeds; a: [Int] = [3]

func g() -> Int! { return nil } // f: () -> Int?, has IUO attribute
let y1 = g() // succeeds; y1: Int? = .None
let y2: Int? = g() // succeeds; y2: Int? = .None
let y3: Int! = g() // succeeds; y3: Int? = .None, has IUO attribute
let y4: Int = g() // traps
let b1 = [g()] // succeeds; b: [Int?] = [.None]
let b2: [Int!] = [g()] // illegal, nested IUO type
let b3: [Int] = [g()] // traps

func p<T>(x: T) { print(x) }
p(f()) // prints "Optional(3)"; p is instantiated with T = Int?

if let x5 = f() {
  // executes, with x4: Int = 3
}
if let y5 = g() {
  // does not execute
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#impact-on-existing-code>Impact on existing code

Variable bindings which previously had inferred type T! from their binding on the right-hand side will now have type T?. The compiler will emit an error at sites where those bound variables are used in a context that demands a non-optional type and suggest that the value be forced with the ! operator.

Explicitly written nested IUO types (like [Int!]) will have to be rewritten to use the corresponding optional type ([Int?]) or non-optional type ([Int]) depending on what's more appropriate for the context. However, most declarations with non-nested IUO type will continue to work as they did before.

It will still be possible to declare IUO properties, so the following deferred initialization pattern will still be possible:

struct S {
  var x: Int!
  init() {}
  func initLater(x someX: Int) { x = someX }
}
<https://github.com/cwillmor/swift-evolution/blob/89971a8162eba3aeb238d47772cda295a02cc585/proposals/0000-abolish-iuo.md#future-directions>Future directions

Because this proposal changes the IUO-ness of a declaration from being part of its type to being an attribute of the declaration, it might make sense to changes the syntactic representation of the attribute to match, e.g. by creating a new @implicitly_unwrapped attribute on declarations:

let x3: Int! = f() // !-based syntax
@implicitly_unwrapped let x3: Int? = f() // attribute-based syntax

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


(Chris Lattner) #11

Right, I’d add:

3. IUO is important for existing C or ObjC codebases that want to move incrementally to Swift through the mix-and-match story. It would be unfortunate to require a nullability audit of everything that came in before you’d have a useful API to work with.

-Chris

···

On Mar 16, 2016, at 6:44 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Let me play devil’s advocate: why not just get rid of implicit unwrapping entirely?

Apple’s Objective-C APIs have had plenty of time to be audited by now.

Two reasons:

1. There are still a number of obscure Apple frameworks which have not been audited.

2. Not all imported code comes from Apple frameworks. In particular, Linux is a whole new world of unaudited—and frankly, probably never-going-to-be-audited in large part—code. Each time Swift moves to a new platform, it will need implicit unwrapping again for a few years while the major libraries get audited. Burning your ships is only a good motivational strategy if you don't need to go anywhere else.


(Chris Willmore) #12

The most significant one is that I think that describing this in terms of an IUO attribute (which is an internal implementation detail) makes the proposal more confusing than necessary for the non-compiler hackers. :slight_smile:

For what it's worth, I actually find it really helpful to have a way to talk about these kinds of features without sugar. I spent most of this proposal going "So, does that mean `Int!` is now `@implicitly_unwrapped Optional<Int>`?”

Not quite. It means “let x: Int!” is now “@implicitly_unwrapped let x: Int?” (supposing one could spell the attribute out like that). That is, the IUO attribute is attached to the declaration of the variable instead of its type.

It's particularly important in this case because `!` implies `?`; there's a lot of magic going on here. Without a completely unambiguous way to write about this behavior, it's hard to talk about it precisely.

For instance, I have two questions for the proposal's author:

* Would the declaration `Int?!` mean `@implicitly_unwrapped Optional<Int>` or `@implicitly_unwrapped Optional<Optional<Int>>`?

The latter, modulo the correction above.

* You say that things like `[Int!]` and `(Int!, Int!)` (`Array<@implicitly_unwrapped Optional<Int>>` and `(@implicitly_unwrapped Optional<Int>, @implicitly_unwrapped Optional<Int>)`) are illegal; are `Int!?` and `Int!!` (`Optional<@implicitly_unwrapped Optional<Int>>` and `@implicitly_unwrapped Optional<@implicitly_unwrapped Optional<Int>>`) illegal as well? (Actually, having written this out explicitly, I'm now fairly confident of the answer: yes, they are illegal.)

Correct; they’re illegal because the “!” token doesn’t appear at the outermost level and therefore there’s no decl to attach the IUO attribute to.
— Chris W.

···

On Mar 16, 2016, at 5:34 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

These kinds of questions are hard to pose unless we have a language to discuss them in, even if that language is rarely actually used when we write code.

--
Brent Royal-Gordon
Architechies


(Chris Willmore) #13

These are excellent points, Brent. Many, many Apple Objective-C APIs have not yet been audited for nullability, and IUOs remain a useful tool until they are — that’s the main reason we’re not proposing getting rid of them entirely. I hadn’t considered Linux but that’s a compelling argument as well.
— Chris W.

···

On Mar 16, 2016, at 6:44 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

Let me play devil’s advocate: why not just get rid of implicit unwrapping entirely?

Apple’s Objective-C APIs have had plenty of time to be audited by now.

Two reasons:

1. There are still a number of obscure Apple frameworks which have not been audited.

2. Not all imported code comes from Apple frameworks. In particular, Linux is a whole new world of unaudited—and frankly, probably never-going-to-be-audited in large part—code. Each time Swift moves to a new platform, it will need implicit unwrapping again for a few years while the major libraries get audited. Burning your ships is only a good motivational strategy if you don't need to go anywhere else.


(Jed Lewison) #14

For this scenario, would you be able to implicitly force-unwrap when a non-optional is not required, like:

  controller.emailTextField.minimumFontSize = 12

Or would you have to say:

  controller.emailTextField?.minimumFontSize = 12

If the former, would fontSize be an Optional<CGFloat> or a CGFloat (non-optional)?

    let fontSize = controller.emailTextField.minimumFontSize

As a user, I’m not sure which I’d expect. Given the behavior of let textField = controller.emailTextField, it seems like i’d expect fontSize to be an Optional<CGFloat>. Then again, if I’m allowed to implicitly unwrap emailTextField, it also doesn’t make any sense for fontSize to be an Optional. (I’m assuming that there would not be a circumstance where the IUO-ableness of the value would be preserved.)

On a different note: As a general rule, I’m +1_000_000 on anything that makes IUO and force-unwrapping less common, so anything with the subject “Abolish IUO Type" makes me smile.

···

On Mar 17, 2016, at 12:16 AM, Chris Willmore via swift-evolution <swift-evolution@swift.org> wrote:

To run with the example above, emailTextField would have type UITextField? but, because it’s an IUO declaration, it would still be usable in contexts that required non-optional UITextField. What would change is that if you were to say, e.g.

let textField = controller.emailTextField

then textField would have type UITextField?. But you could still say

formView.addSubview(controller.emailTextField)


(Chris Lattner) #15

I agree that this is the most straight-forward thing to do. Chris, please add a mention of this to the proposal so that the review discussion considers it. Thanks!

-Chris

···

On Mar 18, 2016, at 11:36 AM, Chris Willmore via swift-evolution <swift-evolution@swift.org> wrote:

typedef void (^CallbackBlock)(FDataSnapshot *snapshot);

The parameter in the block gets converted into a IUO, I ended up releasing an app that crashed due to that IUO being nil.

The code that crashed was something like this

object.observe {
$0.doSomething()
}

There is no way to tell that the $0 was a IUO. The compiler didn't force me to confirm in it in some way using a ! and unless I remembered to check the header I would have a crash.

How would this work under your proposal ?

This is a great question. I think it would make the most sense to import the CallbackBlock type as (FDataSnapshot?) -> (), since there’s no decl to hang the IUO attribute onto. Then $0 ends up with type FDataSnapshot? (i.e. Optional<FDataSnapshot>), and the compiler would not allow you to simply call doSomething() on $0 without forcing it first.


(Chris Willmore) #16

To run with the example above, emailTextField would have type UITextField? but, because it’s an IUO declaration, it would still be usable in contexts that required non-optional UITextField. What would change is that if you were to say, e.g.

let textField = controller.emailTextField

then textField would have type UITextField?. But you could still say

formView.addSubview(controller.emailTextField)

For this scenario, would you be able to implicitly force-unwrap when a non-optional is not required, like:

  controller.emailTextField.minimumFontSize = 12

Or would you have to say:

  controller.emailTextField?.minimumFontSize = 12

The first one. The type-checked expression would force controller.emailTextField.

If the former, would fontSize be an Optional<CGFloat> or a CGFloat (non-optional)?

    let fontSize = controller.emailTextField.minimumFontSize

It would be a (non-optional) CGFloat. Neither of these is different from current IUO behavior.

As a user, I’m not sure which I’d expect. Given the behavior of let textField = controller.emailTextField, it seems like i’d expect fontSize to be an Optional<CGFloat>. Then again, if I’m allowed to implicitly unwrap emailTextField, it also doesn’t make any sense for fontSize to be an Optional.

Yes, this is a little weird. But any attempt to remove the IUO type from the Swift type system, without removing the notion of IUOs entirely, runs into this sort of substitution-principle violation. It is not possible to pull an IUO sub-expression of an expression out into a temporary variable and have it type-check the same way without inferring the intermediate variable as IUO as well, a behavior that we explicitly wish to avoid.

(I’m assuming that there would not be a circumstance where the IUO-ableness of the value would be preserved.)

The variable that the value is bound to could be explicitly marked as IUO. Otherwise, you’re correct.

On a different note: As a general rule, I’m +1_000_000 on anything that makes IUO and force-unwrapping less common, so anything with the subject “Abolish IUO Type" makes me smile.

I’m glad we both feel that way!
— Chris Willmore

···

On Mar 17, 2016, at 1:45 PM, Jed Lewison <jed.lewison@icloud.com> wrote:

On Mar 17, 2016, at 12:16 AM, Chris Willmore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Jed Lewison) #17

Sounds good to me. I’ll admit, I’m looking forward to the day when you have to explicitly use the force operator if you want/need to unsafely unwrap optionals, but this seems like a positive step in that direction.

···

On Mar 17, 2016, at 4:56 PM, Chris Willmore <cwillmore@apple.com> wrote:

On Mar 17, 2016, at 1:45 PM, Jed Lewison <jed.lewison@icloud.com <mailto:jed.lewison@icloud.com>> wrote:

On Mar 17, 2016, at 12:16 AM, Chris Willmore via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

To run with the example above, emailTextField would have type UITextField? but, because it’s an IUO declaration, it would still be usable in contexts that required non-optional UITextField. What would change is that if you were to say, e.g.

let textField = controller.emailTextField

then textField would have type UITextField?. But you could still say

formView.addSubview(controller.emailTextField)

For this scenario, would you be able to implicitly force-unwrap when a non-optional is not required, like:

  controller.emailTextField.minimumFontSize = 12

Or would you have to say:

  controller.emailTextField?.minimumFontSize = 12

The first one. The type-checked expression would force controller.emailTextField.

If the former, would fontSize be an Optional<CGFloat> or a CGFloat (non-optional)?

    let fontSize = controller.emailTextField.minimumFontSize

It would be a (non-optional) CGFloat. Neither of these is different from current IUO behavior.

As a user, I’m not sure which I’d expect. Given the behavior of let textField = controller.emailTextField, it seems like i’d expect fontSize to be an Optional<CGFloat>. Then again, if I’m allowed to implicitly unwrap emailTextField, it also doesn’t make any sense for fontSize to be an Optional.

Yes, this is a little weird. But any attempt to remove the IUO type from the Swift type system, without removing the notion of IUOs entirely, runs into this sort of substitution-principle violation. It is not possible to pull an IUO sub-expression of an expression out into a temporary variable and have it type-check the same way without inferring the intermediate variable as IUO as well, a behavior that we explicitly wish to avoid.

(I’m assuming that there would not be a circumstance where the IUO-ableness of the value would be preserved.)

The variable that the value is bound to could be explicitly marked as IUO. Otherwise, you’re correct.

On a different note: As a general rule, I’m +1_000_000 on anything that makes IUO and force-unwrapping less common, so anything with the subject “Abolish IUO Type" makes me smile.

I’m glad we both feel that way!
— Chris Willmore