Pitch: Modify the meaning of IBOutlet to remove the ! from the type


(Daniel Steinberg) #1

I would like to propose we modify the meaning of @IBOutlet in light of the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I think this fits in with the current Swift 3 goals.

Currently we use “var” and “!” when we declare an outlet like this:

@IBOutlet weak var myLabel: UILabel!

The “!” in the declaration allows us to use the outlet like this without unwrapping it

myLabel.text = “Hello"

We use “var” and “UILabel!" because myLabel starts its life out as nil and does not have a value until the connection is made. i.e. myLabel must be an optional if it accepts nil and the type is UILabel! instead of UILabel? so that we don’t have to unwrap it each time we use it.

If we break the connection to the UILabel instance we crash at runtime for attempting to unwrap nil.

Given this, I propose that we be able to write

@IBOutlet weak let myLabel: UILabel

In this case @IBOutlet has a meaning somewhat similar to lazy - it’s not that myLabel doesn’t exist until we first call it, but @IBOutlet indicates that myLabel should exist before we call it.

If the connection isn’t made and myLabel doesn’t exist, we should crash as we do now. If the connection is not made in the nib or storyboard, this will crash at development time.

This removes a case in which we use var - not because we want to change the value of a property but because of a detail in the tooling.

This change also removes a case in which we use an Optional again for a detail in lifecycle and tooling.

Best,

Daniel


(Vladimir) #2

Correct me if I'm wrong, but `weak` reference can not be `let` just by definition: at some point in time such reference *can* become nil.

···

On 18.05.2016 16:22, Daniel Steinberg via swift-evolution wrote:

I would like to propose we modify the meaning of @IBOutlet in light of the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I think this fits in with the current Swift 3 goals.

Currently we use “var” and “!” when we declare an outlet like this:

@IBOutlet weak var myLabel: UILabel!

The “!” in the declaration allows us to use the outlet like this without unwrapping it

myLabel.text = “Hello"

We use “var” and “UILabel!" because myLabel starts its life out as nil and does not have a value until the connection is made. i.e. myLabel must be an optional if it accepts nil and the type is UILabel! instead of UILabel? so that we don’t have to unwrap it each time we use it.

If we break the connection to the UILabel instance we crash at runtime for attempting to unwrap nil.

Given this, I propose that we be able to write

@IBOutlet weak let myLabel: UILabel

In this case @IBOutlet has a meaning somewhat similar to lazy - it’s not that myLabel doesn’t exist until we first call it, but @IBOutlet indicates that myLabel should exist before we call it.

If the connection isn’t made and myLabel doesn’t exist, we should crash as we do now. If the connection is not made in the nib or storyboard, this will crash at development time.

This removes a case in which we use var - not because we want to change the value of a property but because of a detail in the tooling.

This change also removes a case in which we use an Optional again for a detail in lifecycle and tooling.

Best,

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


(Krystof Vasa) #3

Within this proposal, would it be still possible to test the variable against nil?

If yes, then it'd be very confusing, since you'd have a variable declared as non-optional, but you'd be comparing it to nil.

If no, this is not correct since the instance can be executing code before the nib file is loaded and the UI elements connected. Which is again a weird situation where you have variables that when accessed, the app crashes, but you can't check if it's valid.

The @IBOutlet variables are pretty much just dynamic vars with an extra annotation so that IB knows that they can be connected in the UI. This would be causing the annotation to change the type of the variable which is a matter discussed in another thread here as well.

Krystof

···

On May 18, 2016, at 3:22 PM, Daniel Steinberg via swift-evolution <swift-evolution@swift.org> wrote:

I would like to propose we modify the meaning of @IBOutlet in light of the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I think this fits in with the current Swift 3 goals.

Currently we use “var” and “!” when we declare an outlet like this:

@IBOutlet weak var myLabel: UILabel!

The “!” in the declaration allows us to use the outlet like this without unwrapping it

myLabel.text = “Hello"

We use “var” and “UILabel!" because myLabel starts its life out as nil and does not have a value until the connection is made. i.e. myLabel must be an optional if it accepts nil and the type is UILabel! instead of UILabel? so that we don’t have to unwrap it each time we use it.

If we break the connection to the UILabel instance we crash at runtime for attempting to unwrap nil.

Given this, I propose that we be able to write

@IBOutlet weak let myLabel: UILabel

In this case @IBOutlet has a meaning somewhat similar to lazy - it’s not that myLabel doesn’t exist until we first call it, but @IBOutlet indicates that myLabel should exist before we call it.

If the connection isn’t made and myLabel doesn’t exist, we should crash as we do now. If the connection is not made in the nib or storyboard, this will crash at development time.

This removes a case in which we use var - not because we want to change the value of a property but because of a detail in the tooling.

This change also removes a case in which we use an Optional again for a detail in lifecycle and tooling.

Best,

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


(TJ Usiyan) #4

The attribute wouldn't change the behavior. The reference is still
implicitly unwrapped. IB Outlets are, at least currently, IUO by necessity.
I think that this proposal looks to make it less redundant. I didn't fully
spot the use of `let` on the first or second reading but there is another
proposal being pitched for allowing computer properties to be `let`. This
is similar in that regard. From the discussion there, it sounds like that
part might not fit with the core team's vision for the optimizer?

···

On Wed, May 18, 2016 at 10:36 AM, Tony Allevato via swift-evolution < swift-evolution@swift.org> wrote:

Similarly, a weak reference cannot be non-optional. I would be
uncomfortable with an attribute changing that behavior. Having a
non-optional field become nil or crash behind the scenes discards the
safety of the Swift type system.

There are legitimate situations where a class might have unused outlets as
well, where you would want an optional (`?`) type; for example, you could
have an iPad nib that has additional views that aren't present in an iPhone
nib, but both share the same view controller. In that case, you would want
to have some of those outlets still be optional. (Your pitch may not
prevent that behavior, but it's worth pointing out as a use case.)

On Wed, May 18, 2016 at 6:42 AM Vladimir.S via swift-evolution < > swift-evolution@swift.org> wrote:

Correct me if I'm wrong, but `weak` reference can not be `let` just by
definition: at some point in time such reference *can* become nil.

On 18.05.2016 16:22, Daniel Steinberg via swift-evolution wrote:
> I would like to propose we modify the meaning of @IBOutlet in light of
the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I
think this fits in with the current Swift 3 goals.
>
> Currently we use “var” and “!” when we declare an outlet like this:
>
> @IBOutlet weak var myLabel: UILabel!
>
> The “!” in the declaration allows us to use the outlet like this
without unwrapping it
>
> myLabel.text = “Hello"
>
> We use “var” and “UILabel!" because myLabel starts its life out as nil
and does not have a value until the connection is made. i.e. myLabel must
be an optional if it accepts nil and the type is UILabel! instead of
UILabel? so that we don’t have to unwrap it each time we use it.
>
> If we break the connection to the UILabel instance we crash at runtime
for attempting to unwrap nil.
>
> Given this, I propose that we be able to write
>
> @IBOutlet weak let myLabel: UILabel
>
> In this case @IBOutlet has a meaning somewhat similar to lazy - it’s
not that myLabel doesn’t exist until we first call it, but @IBOutlet
indicates that myLabel should exist before we call it.
>
> If the connection isn’t made and myLabel doesn’t exist, we should crash
as we do now. If the connection is not made in the nib or storyboard, this
will crash at development time.
>
> This removes a case in which we use var - not because we want to change
the value of a property but because of a detail in the tooling.
>
> This change also removes a case in which we use an Optional again for a
detail in lifecycle and tooling.
>
> Best,
>
> Daniel
> _______________________________________________
> 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

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


(Tony Allevato) #5

Similarly, a weak reference cannot be non-optional. I would be
uncomfortable with an attribute changing that behavior. Having a
non-optional field become nil or crash behind the scenes discards the
safety of the Swift type system.

There are legitimate situations where a class might have unused outlets as
well, where you would want an optional (`?`) type; for example, you could
have an iPad nib that has additional views that aren't present in an iPhone
nib, but both share the same view controller. In that case, you would want
to have some of those outlets still be optional. (Your pitch may not
prevent that behavior, but it's worth pointing out as a use case.)

···

On Wed, May 18, 2016 at 6:42 AM Vladimir.S via swift-evolution < swift-evolution@swift.org> wrote:

Correct me if I'm wrong, but `weak` reference can not be `let` just by
definition: at some point in time such reference *can* become nil.

On 18.05.2016 16:22, Daniel Steinberg via swift-evolution wrote:
> I would like to propose we modify the meaning of @IBOutlet in light of
the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I
think this fits in with the current Swift 3 goals.
>
> Currently we use “var” and “!” when we declare an outlet like this:
>
> @IBOutlet weak var myLabel: UILabel!
>
> The “!” in the declaration allows us to use the outlet like this without
unwrapping it
>
> myLabel.text = “Hello"
>
> We use “var” and “UILabel!" because myLabel starts its life out as nil
and does not have a value until the connection is made. i.e. myLabel must
be an optional if it accepts nil and the type is UILabel! instead of
UILabel? so that we don’t have to unwrap it each time we use it.
>
> If we break the connection to the UILabel instance we crash at runtime
for attempting to unwrap nil.
>
> Given this, I propose that we be able to write
>
> @IBOutlet weak let myLabel: UILabel
>
> In this case @IBOutlet has a meaning somewhat similar to lazy - it’s not
that myLabel doesn’t exist until we first call it, but @IBOutlet indicates
that myLabel should exist before we call it.
>
> If the connection isn’t made and myLabel doesn’t exist, we should crash
as we do now. If the connection is not made in the nib or storyboard, this
will crash at development time.
>
> This removes a case in which we use var - not because we want to change
the value of a property but because of a detail in the tooling.
>
> This change also removes a case in which we use an Optional again for a
detail in lifecycle and tooling.
>
> Best,
>
> Daniel
> _______________________________________________
> 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


(Michael Peternell) #6

The really nice thing about the "!" operator is that it is always explicit. Either in the variable declaration, or when unwrapping it with "!" or "if let". "@IBOutlet weak var"s should therefore really not introduce an implicit "!". It's just one character, and it's good to see that this is actually an implicitly unwrapped optional. Furthermore, IOUs are made exactly for the case where you have a variable that *can* not be nil (unless you messed something up), but it cannot be proven by the compiler. If it is not a logic error if you try to use such a variable in code and it is nil, you should use a real optional instead. Furthermore, you can also write "@IBOutlet weak var foo: UIBar?" - both are valid. For example, a view controller can also do stuff if the view is not yet loaded.

and yes, "weak let" would break the semantic meaning of "let".

I think Optionals are really very very carefully designed already, and provide a simple(, useful) and consistent model. The description of [optionals, "!", "?", "if let", "weak", "unowned"] can be fully defined in a few sentences, and I'm against anything that just bloats this description without being an essential improvement.

-Michael

···

Am 18.05.2016 um 15:42 schrieb Vladimir.S via swift-evolution <swift-evolution@swift.org>:

Correct me if I'm wrong, but `weak` reference can not be `let` just by definition: at some point in time such reference *can* become nil.

On 18.05.2016 16:22, Daniel Steinberg via swift-evolution wrote:

I would like to propose we modify the meaning of @IBOutlet in light of the accepted proposal SE-0054 Abolish ImplicitlyUnwrappedOptional type. I think this fits in with the current Swift 3 goals.

Currently we use “var” and “!” when we declare an outlet like this:

@IBOutlet weak var myLabel: UILabel!

The “!” in the declaration allows us to use the outlet like this without unwrapping it

myLabel.text = “Hello"

We use “var” and “UILabel!" because myLabel starts its life out as nil and does not have a value until the connection is made. i.e. myLabel must be an optional if it accepts nil and the type is UILabel! instead of UILabel? so that we don’t have to unwrap it each time we use it.

If we break the connection to the UILabel instance we crash at runtime for attempting to unwrap nil.

Given this, I propose that we be able to write

@IBOutlet weak let myLabel: UILabel

In this case @IBOutlet has a meaning somewhat similar to lazy - it’s not that myLabel doesn’t exist until we first call it, but @IBOutlet indicates that myLabel should exist before we call it.

If the connection isn’t made and myLabel doesn’t exist, we should crash as we do now. If the connection is not made in the nib or storyboard, this will crash at development time.

This removes a case in which we use var - not because we want to change the value of a property but because of a detail in the tooling.

This change also removes a case in which we use an Optional again for a detail in lifecycle and tooling.

Best,

Daniel
_______________________________________________
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