Optional comparison operators


(Jacob Bandes-Storch) #1

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil < .some(x)
for any x? Personally, my intuition says that Optional should only provide
a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?,
T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the implicit

promotion from T to T? should be disabled when in an operator context.
Doing so would fix problems like this, but making the code invalid.

A change like this would be source-breaking, so if the core team has
recommendations for how to handle these issues, now is probably the time to
get it done.

Jacob


(Jacob Bandes-Storch) #2

Bump for Swift 3.

···

On Thu, Jul 7, 2016 at 2:37 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil <
.some(x) for any x? Personally, my intuition says that Optional should only
provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?,
T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the

implicit promotion from T to T? should be disabled when in an operator
context. Doing so would fix problems like this, but making the code
invalid.

A change like this would be source-breaking, so if the core team has
recommendations for how to handle these issues, now is probably the time to
get it done.

Jacob


(David Sweeris) #3

Why not have them return a `Bool?`? If both arguments are non-nil, it can return the results of the comparison, otherwise it can return nil.

- Dave Sweeris

···

On Jul 7, 2016, at 16:37, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil < .some(x) for any x? Personally, my intuition says that Optional should only provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?, T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the implicit promotion from T to T? should be disabled when in an operator context. Doing so would fix problems like this, but making the code invalid.

A change like this would be source-breaking, so if the core team has recommendations for how to handle these issues, now is probably the time to get it done.

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


(Mark Lacey) #4

Hi Jacob,

···

On Jul 11, 2016, at 4:23 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Bump for Swift 3.

On Thu, Jul 7, 2016 at 2:37 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:
These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil < .some(x) for any x? Personally, my intuition says that Optional should only provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?, T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the implicit promotion from T to T? should be disabled when in an operator context. Doing so would fix problems like this, but making the code invalid.

A change like this would be source-breaking, so if the core team has recommendations for how to handle these issues, now is probably the time to get it done.

I overlooked your previous message on this.

I’m actually writing up a proposal for this now, and have an implementation that I’ve done a bit of testing with.

I’m hoping to get the proposal out in the next couple days.

Mark


(Saagar Jha) #5

Correct me if I’m wrong, but wouldn’t you have to unwrap every comparison then?

···

On Jul 11, 2016, at 20:02, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

Why not have them return a `Bool?`? If both arguments are non-nil, it can return the results of the comparison, otherwise it can return nil.

- Dave Sweeris

On Jul 7, 2016, at 16:37, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil < .some(x) for any x? Personally, my intuition says that Optional should only provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?, T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar:// <rdar://>16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the implicit promotion from T to T? should be disabled when in an operator context. Doing so would fix problems like this, but making the code invalid.

A change like this would be source-breaking, so if the core team has recommendations for how to handle these issues, now is probably the time to get it done.

Jacob
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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


(Jacob Bandes-Storch) #6

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in some
other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think
it would be more convenient in some cases than unwrapping the individual
values before comparing them.

Jacob

···

On Mon, Jul 11, 2016 at 8:08 PM, Saagar Jha <saagarjha28@gmail.com> wrote:

Correct me if I’m wrong, but wouldn’t you have to unwrap every comparison
then?

On Jul 11, 2016, at 20:02, David Sweeris via swift-evolution < > swift-evolution@swift.org> wrote:

Why not have them return a `Bool?`? If both arguments are non-nil, it can
return the results of the comparison, otherwise it can return nil.

- Dave Sweeris

On Jul 7, 2016, at 16:37, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil <
.some(x) for any x? Personally, my intuition says that Optional should only
provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?,
T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the

implicit promotion from T to T? should be disabled when in an operator
context. Doing so would fix problems like this, but making the code
invalid.

A change like this would be source-breaking, so if the core team has
recommendations for how to handle these issues, now is probably the time to
get it done.

Jacob

_______________________________________________
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


(Chris Lattner) #7

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

···

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.


(Mark Lacey) #8

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal: https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect this should be a separate proposal, but I can roll that into this one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected for review.

Mark

···

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

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


(Chris Lattner) #9

I think it makes sense to keep removal of the non-equality comparisons a separate proposal.

Here are some nit-picky comments:

I’d suggest adding quotes:

… by making the notion of “having" or "not having" a value explicit.

Missing a let/var before the first x in:

func returnsOptional() -> Int? {
  x: Int = ...
  return x
}

I would move “Proposed Solution” before “Motivation” and just call it “Proposal”. Otherwise the motivation section doesn’t make sense to read in order.

I’d add to this:
"Both of these examples represent cases where the silent behavior could potentially hide bugs or confuse readers of the code.”

… “, it would be better to reject the code as a type error."

If this is relating to implementation details of the standard library, then it should be omitted from the proposal. The following paragraph also makes sense to revise if you drop this:
"Additionally the standard library has approximately a half a dozen locations where optionals are compared to non-optional values which will need to be updated to explicitly cast one operand to an optional.”

In this paragraph, I’d recommend changing the wording to be specific and opinionated (saying that “Optional” is the right answer). If you want to raise specific alternatives for consideration, please add it to “alternatives considered” at the end:
"This conversion can currently be accomplished by using Optional() (preferable) or alternately .some(). We could also consider adding a new top-level function for this purpose, but unless it provides additional clarity, it seems like Optional() is reasonable and quite prominent."

Keeping the body of the proposal opinionated makes the review periods more useful because people know what is specifically being proposed.

"In a survey of six projects” -> Can you explicitly share the name of any of the projects?

Otherwise, LGTM. When you’re happy with it, please submit a PR for swift-evolution repo, I’ll review managerize it,

-Chris

···

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal: https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect this should be a separate proposal, but I can roll that into this one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected for review.


(Mark Lacey) #10

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal: https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect this should be a separate proposal, but I can roll that into this one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected for review.

I think it makes sense to keep removal of the non-equality comparisons a separate proposal.

Here are some nit-picky comments:

I’d suggest adding quotes:

… by making the notion of “having" or "not having" a value explicit.

Missing a let/var before the first x in:

func returnsOptional() -> Int? {
  x: Int = ...
  return x
}

I would move “Proposed Solution” before “Motivation” and just call it “Proposal”. Otherwise the motivation section doesn’t make sense to read in order.

I’d add to this:
"Both of these examples represent cases where the silent behavior could potentially hide bugs or confuse readers of the code.”

… “, it would be better to reject the code as a type error."

If this is relating to implementation details of the standard library, then it should be omitted from the proposal. The following paragraph also makes sense to revise if you drop this:
"Additionally the standard library has approximately a half a dozen locations where optionals are compared to non-optional values which will need to be updated to explicitly cast one operand to an optional.”

Thanks for the great feedback. I have most of it addressed, but I’m not sure what you’re referring to with “If this is relating to implementation details of the standard library…”? Do you mean the functions I called out that need to be added?

I can remove that, but I thought it was worth calling out despite the fact that they are just overloads. If it’s not necessary to do so, I’ll delete that section (although there aren’t many details left in the “Detailed design” at that point).

Mark

···

On Jul 11, 2016, at 9:54 PM, Chris Lattner <clattner@apple.com> wrote:

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com <mailto:mark.lacey@apple.com>> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In this paragraph, I’d recommend changing the wording to be specific and opinionated (saying that “Optional” is the right answer). If you want to raise specific alternatives for consideration, please add it to “alternatives considered” at the end:
"This conversion can currently be accomplished by using Optional() (preferable) or alternately .some(). We could also consider adding a new top-level function for this purpose, but unless it provides additional clarity, it seems like Optional() is reasonable and quite prominent."

Keeping the body of the proposal opinionated makes the review periods more useful because people know what is specifically being proposed.

"In a survey of six projects” -> Can you explicitly share the name of any of the projects?

Otherwise, LGTM. When you’re happy with it, please submit a PR for swift-evolution repo, I’ll review managerize it,

-Chris


(Jacob Bandes-Storch) #11

Mark,
Thanks for writing this up. Just to clarify, will these still work if your
proposal is implemented?

    let x: Int?
    let y: Int
    struct NotEquatable {}
    let z: NotEquatable?

    x == y; x != y
    x == nil; x != nil
    z == nil; z != nil

I would hope that these continue to work. If any changes need to be made to
ensure that, please make sure they're included in the proposal too.

Jacob

···

On Mon, Jul 11, 2016 at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in some
other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think
it would be more convenient in some cases than unwrapping the individual
values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so
would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal:
https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect
this should be a separate proposal, but I can roll that into this one if
it’s desired.

I’ll update the proposal as the discussion continues until it’s selected
for review.

Mark

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


(Jacob Bandes-Storch) #12

Here's a draft. Feedback welcome:

https://github.com/jtbandes/swift-evolution/blob/master/proposals/0122-remove-optional-comparison-operators.md

···

On Mon, Jul 11, 2016 at 9:54 PM, Chris Lattner <clattner@apple.com> wrote:

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in some
other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think
it would be more convenient in some cases than unwrapping the individual
values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so
would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal:
https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect
this should be a separate proposal, but I can roll that into this one if
it’s desired.

I’ll update the proposal as the discussion continues until it’s selected
for review.

I think it makes sense to keep removal of the non-equality comparisons a
separate proposal.


(Jacob Bandes-Storch) #13

Great, thanks Mark! I look forward to it.

···

On Mon, Jul 11, 2016 at 4:31 PM, Mark Lacey <mark.lacey@apple.com> wrote:

Hi Jacob,

On Jul 11, 2016, at 4:23 PM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

Bump for Swift 3.

On Thu, Jul 7, 2016 at 2:37 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:

These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil <
.some(x) for any x? Personally, my intuition says that Optional should only
provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?,
T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar://16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the

implicit promotion from T to T? should be disabled when in an operator
context. Doing so would fix problems like this, but making the code
invalid.

A change like this would be source-breaking, so if the core team has
recommendations for how to handle these issues, now is probably the time to
get it done.

I overlooked your previous message on this.

I’m actually writing up a proposal for this now, and have an
implementation that I’ve done a bit of testing with.

I’m hoping to get the proposal out in the next couple days.

Mark


(Mark Lacey) #14

Mark,
Thanks for writing this up. Just to clarify, will these still work if your proposal is implemented?

    let x: Int?
    let y: Int
    struct NotEquatable {}
    let z: NotEquatable?

    x == y; x != y
    x == nil; x != nil
    z == nil; z != nil

I would hope that these continue to work. If any changes need to be made to ensure that, please make sure they're included in the proposal too.

The last four would work, but the first two (x == y and x != y) would not because they still involve coercing y to an optional.

Similarly, === and !== on reference types where one is an optional would require coercing one side, and would not be accepted without an explicit cast using Optional().

I’m curious what the motivation is for further special casing these operators. They do occur more in practice than <, <=, >, >= (in fact most of the source updates I had to make were due to === and !==, with == and != a close second), but overall these are still quite uncommon from what I’ve seen.

If you’d like I can certainly update the “alternatives considered” to include the suggestion that we add overloads for (T, T?) and (T?, T) for those four operators.

Mark

···

On Jul 11, 2016, at 11:55 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

Jacob

On Mon, Jul 11, 2016 at 9:35 PM, Mark Lacey <mark.lacey@apple.com <mailto:mark.lacey@apple.com>> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal: https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect this should be a separate proposal, but I can roll that into this one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected for review.

Mark

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


(David Hart) #15

There’s something I don’t understand about the proposal. How can the following code still be valid if the proposal is accepted:

let x: Int! = 5
let y: Int? = 7
print(x < y) // true

Isn’t there going to be a problem coercing y?

David.

···

On 12 Jul 2016, at 08:22, Mark Lacey via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 9:54 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com <mailto:mark.lacey@apple.com>> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

You'd have to unwrap it, or use the ??/==/!= operators: https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older email (which somehow didn't make it to gmane's archive, but it's quoted in some other messages <http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think it would be more convenient in some cases than unwrapping the individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal: https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect this should be a separate proposal, but I can roll that into this one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected for review.

I think it makes sense to keep removal of the non-equality comparisons a separate proposal.

Here are some nit-picky comments:

I’d suggest adding quotes:

… by making the notion of “having" or "not having" a value explicit.

Missing a let/var before the first x in:

func returnsOptional() -> Int? {
  x: Int = ...
  return x
}

I would move “Proposed Solution” before “Motivation” and just call it “Proposal”. Otherwise the motivation section doesn’t make sense to read in order.

I’d add to this:
"Both of these examples represent cases where the silent behavior could potentially hide bugs or confuse readers of the code.”

… “, it would be better to reject the code as a type error."

If this is relating to implementation details of the standard library, then it should be omitted from the proposal. The following paragraph also makes sense to revise if you drop this:
"Additionally the standard library has approximately a half a dozen locations where optionals are compared to non-optional values which will need to be updated to explicitly cast one operand to an optional.”

Thanks for the great feedback. I have most of it addressed, but I’m not sure what you’re referring to with “If this is relating to implementation details of the standard library…”? Do you mean the functions I called out that need to be added?

I can remove that, but I thought it was worth calling out despite the fact that they are just overloads. If it’s not necessary to do so, I’ll delete that section (although there aren’t many details left in the “Detailed design” at that point).

Mark

In this paragraph, I’d recommend changing the wording to be specific and opinionated (saying that “Optional” is the right answer). If you want to raise specific alternatives for consideration, please add it to “alternatives considered” at the end:
"This conversion can currently be accomplished by using Optional() (preferable) or alternately .some(). We could also consider adding a new top-level function for this purpose, but unless it provides additional clarity, it seems like Optional() is reasonable and quite prominent."

Keeping the body of the proposal opinionated makes the review periods more useful because people know what is specifically being proposed.

"In a survey of six projects” -> Can you explicitly share the name of any of the projects?

Otherwise, LGTM. When you’re happy with it, please submit a PR for swift-evolution repo, I’ll review managerize it,

-Chris

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


(Jacob Bandes-Storch) #16

I've submitted a PR for my proposal to remove these versions of </<=/>/>=
at https://github.com/apple/swift-evolution/pull/425.

···

On Tue, Jul 12, 2016 at 12:03 AM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

On Mon, Jul 11, 2016 at 9:54 PM, Chris Lattner <clattner@apple.com> wrote:

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution < >> swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution < >> swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in some
other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I
think it would be more convenient in some cases than unwrapping the
individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so
would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal:
https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I
suspect this should be a separate proposal, but I can roll that into this
one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected
for review.

I think it makes sense to keep removal of the non-equality comparisons a
separate proposal.

Here's a draft. Feedback welcome:

https://github.com/jtbandes/swift-evolution/blob/master/proposals/0122-remove-optional-comparison-operators.md


(Chris Lattner) #17

I’m referring to this part of the proposal:

"Additionally the standard library has approximately a half a dozen locations where optionals are compared to non-optional values which will need to be updated to explicitly cast one operand to an optional.”

I’m just saying that the internal implementation details of the standard library are typically considered part of an evolution proposal, only the public API impact.

-Chris

···

On Jul 11, 2016, at 11:22 PM, Mark Lacey <mark.lacey@apple.com> wrote:

If this is relating to implementation details of the standard library, then it should be omitted from the proposal. The following paragraph also makes sense to revise if you drop this:
"Additionally the standard library has approximately a half a dozen locations where optionals are compared to non-optional values which will need to be updated to explicitly cast one operand to an optional.”

Thanks for the great feedback. I have most of it addressed, but I’m not sure what you’re referring to with “If this is relating to implementation details of the standard library…”? Do you mean the functions I called out that need to be added?

I can remove that, but I thought it was worth calling out despite the fact that they are just overloads. If it’s not necessary to do so, I’ll delete that section (although there aren’t many details left in the “Detailed design” at that point).


(Mark Lacey) #18

Great, thanks Mark! I look forward to it.

To be clear, I’m specifically looking at making the change to remove the coercion from T to T? for operator arguments.

I agree there might be other things worth looking at regarding operators that take optionals, but I’m not currently looking at those issues.

Mark

···

On Jul 11, 2016, at 4:32 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

On Mon, Jul 11, 2016 at 4:31 PM, Mark Lacey <mark.lacey@apple.com <mailto:mark.lacey@apple.com>> wrote:
Hi Jacob,

On Jul 11, 2016, at 4:23 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Bump for Swift 3.

On Thu, Jul 7, 2016 at 2:37 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:
These operators cause some potential for confusion:

    public func <<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func ><T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func <=<T : Comparable>(lhs: T?, rhs: T?) -> Bool
    public func >=<T : Comparable>(lhs: T?, rhs: T?) -> Bool

1. The meaning of T? < T? is not immediately obvious (Why is nil < .some(x) for any x? Personally, my intuition says that Optional should only provide a partial order, with .none not being ordered w.r.t. .some(x).)

2. Even if the meaning is understood, it can be surprising when the (T?, T?) -> Bool version is used instead of (T, T) -> Bool.

Prior discussion:
- http://thread.gmane.org/gmane.comp.lang.swift.devel/2089
- http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095
- rdar:// <>16966712&22833869
- Replies to https://twitter.com/jtbandes/status/646914031433871364

In the swift-dev thread from May, Chris said:

One of the ideas that Joe Pamer has been discussing is whether the implicit promotion from T to T? should be disabled when in an operator context. Doing so would fix problems like this, but making the code invalid.

A change like this would be source-breaking, so if the core team has recommendations for how to handle these issues, now is probably the time to get it done.

I overlooked your previous message on this.

I’m actually writing up a proposal for this now, and have an implementation that I’ve done a bit of testing with.

I’m hoping to get the proposal out in the next couple days.

Mark


(Jacob Bandes-Storch) #19

David,
The proposal Mark is working on doesn't remove the operators which accept
optional values. It simply removes the ability to pass non-optional values
to them without explicit casting/coercion. In that example y doesn't need
to be coerced.

I'm currently writing up a separate proposal to remove these operators. The
two issues are largely orthogonal.

Jacob

···

On Mon, Jul 11, 2016 at 11:49 PM, David Hart via swift-evolution < swift-evolution@swift.org> wrote:

There’s something I don’t understand about the proposal. How can the
following code still be valid if the proposal is accepted:

let x: Int! = 5
let y: Int? = 7
print(x < y) // true

Isn’t there going to be a problem coercing y?

David.

On 12 Jul 2016, at 08:22, Mark Lacey via swift-evolution < > swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 9:54 PM, Chris Lattner <clattner@apple.com> wrote:

On Jul 11, 2016, at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in
some other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I think
it would be more convenient in some cases than unwrapping the individual
values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so
would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal:
https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I suspect
this should be a separate proposal, but I can roll that into this one if
it’s desired.

I’ll update the proposal as the discussion continues until it’s selected
for review.

I think it makes sense to keep removal of the non-equality comparisons a
separate proposal.

Here are some nit-picky comments:

I’d suggest adding quotes:

… by making the notion of “having" or "not having" a value explicit.

Missing a let/var before the first x in:

func returnsOptional() -> Int? {
  x: Int = ...
  return x
}

I would move “Proposed Solution” before “Motivation” and just call it
“Proposal”. Otherwise the motivation section doesn’t make sense to read in
order.

I’d add to this:
"Both of these examples represent cases where the silent behavior could
potentially hide bugs or confuse readers of the code.”

… “, it would be better to reject the code as a type error."

If this is relating to implementation details of the standard library,
then it should be omitted from the proposal. The following paragraph also
makes sense to revise if you drop this:
"Additionally the standard library has approximately a half a dozen
locations where optionals are compared to non-optional values which will
need to be updated to explicitly cast one operand to an optional.”

Thanks for the great feedback. I have most of it addressed, but I’m not
sure what you’re referring to with “If this is relating to implementation
details of the standard library…”? Do you mean the functions I called out
that need to be added?

I can remove that, but I thought it was worth calling out despite the fact
that they are just overloads. If it’s not necessary to do so, I’ll delete
that section (although there aren’t many details left in the “Detailed
design” at that point).

Mark

In this paragraph, I’d recommend changing the wording to be specific and
opinionated (saying that “Optional” is the right answer). If you want to
raise specific alternatives for consideration, please add it to
“alternatives considered” at the end:
"This conversion can currently be accomplished by
using Optional() (preferable) or alternately .some(). We could also
consider adding a new top-level function for this purpose, but unless it
provides additional clarity, it seems like Optional() is reasonable and
quite prominent."

Keeping the body of the proposal opinionated makes the review periods more
useful because people know what is specifically being proposed.

"In a survey of six projects” -> Can you explicitly share the name of any
of the projects?

Otherwise, LGTM. When you’re happy with it, please submit a PR for
swift-evolution repo, I’ll review managerize it,

-Chris

_______________________________________________
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


(Jacob Bandes-Storch) #20

Okay, I guess it's fair that (T, T?) and (T?, T) overloads should have to
be a separate proposal.

My personal motivation is mostly anecdotal; I've found them quite useful,
and I wouldn't say they're uncommon. Some use cases off the top of my head:
- checking whether a dictionary contains a particular value for a key
- checking whether an optional ivar (such as "selectedIndex: Int?")
contains a particular value ("if tappedIndex == selectedIndex")

Jacob

···

On Tue, Jul 12, 2016 at 12:09 AM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 11:55 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:

Mark,
Thanks for writing this up. Just to clarify, will these still work if your
proposal is implemented?

    let x: Int?
    let y: Int
    struct NotEquatable {}
    let z: NotEquatable?

    x == y; x != y
    x == nil; x != nil
    z == nil; z != nil

I would hope that these continue to work. If any changes need to be made
to ensure that, please make sure they're included in the proposal too.

The last four would work, but the first two (x == y and x != y) would not
because they still involve coercing y to an optional.

Similarly, === and !== on reference types where one is an optional would
require coercing one side, and would not be accepted without an explicit
cast using Optional().

I’m curious what the motivation is for further special casing these
operators. They do occur more in practice than <, <=, >, >= (in fact most
of the source updates I had to make were due to === and !==, with == and !=
a close second), but overall these are still quite uncommon from what I’ve
seen.

If you’d like I can certainly update the “alternatives considered” to
include the suggestion that we add overloads for (T, T?) and (T?, T) for
those four operators.

Mark

Jacob

On Mon, Jul 11, 2016 at 9:35 PM, Mark Lacey <mark.lacey@apple.com> wrote:

On Jul 11, 2016, at 9:12 PM, Chris Lattner via swift-evolution < >> swift-evolution@swift.org> wrote:

On Jul 11, 2016, at 8:14 PM, Jacob Bandes-Storch via swift-evolution < >> swift-evolution@swift.org> wrote:

You'd have to unwrap it, or use the ??/==/!= operators:
https://gist.github.com/jtbandes/9d88cc83ceceb6c62f38

I'd be okay with </<=/>/>= returning Bool?, as I suggested in an older
email (which somehow didn't make it to gmane's archive, but it's quoted in some
other messages
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/10095>). I
think it would be more convenient in some cases than unwrapping the
individual values before comparing them.

I’d be strongly opposed to those operator returning “Bool?”. Doing so
would prevent conforming to Comparable and would be extremely surprising.

-Chris

I just pushed the current draft of the proposal:
https://github.com/rudkx/swift-evolution/blob/eliminate-value-to-optional-coercion/proposals/0000-disallow-value-to-optional-coercion-in-operator-arguments.md

I haven’t addressed removal of the ordered comparison operators. I
suspect this should be a separate proposal, but I can roll that into this
one if it’s desired.

I’ll update the proposal as the discussion continues until it’s selected
for review.

Mark

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