Optional comparison operators

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

Thanks, LGTM, I merged and kicked it off.

-Chris

···

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

On Tue, Jul 12, 2016 at 12:03 AM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:
On Mon, 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: Bool? "truth" table · GitHub

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&gt;\). 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

Right; it's the standard library team's job to suffer for the sake of
our users :-). If improving our APIs means work for us, that's no
problem.

That said, actually *implementing and testing* the proposal proves that
it is implementable, and observing its impact on the standard library
can provide useful information about the likely impact on user code. A
pull request supporting any proposal is always appreciated and makes it
easier to accept.

hint-hint-ly y'rs,

···

on Tue Jul 12 2016, Chris Lattner <swift-evolution@swift.org> wrote:

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).

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.

--
Dave

Personally I think we should just remove these optional-taking variants of
the comparison operators. Does anyone agree/disagree?

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were
removed, we might want to add (T, T?) and (T?, T) versions. Are there any
other operators that would be affected by your proposal? If not, removing
the optional </<=/>/>= would obviate the need to remove coercion.

Jacob

···

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

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

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

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.

Sure, I mean uncommon in the sense that in the projects I’ve looked at I’m seeing them perhaps once every 1,000-2,000 lines of commented code, not uncommon in the sense that you will almost never see them in practice. I’m sure for some projects it’s going to be much more often than others.

Mark

···

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

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 <mailto:mark.lacey@apple.com>> wrote:

On Jul 11, 2016, at 11:55 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto: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 <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: Bool? "truth" table · GitHub

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&gt;\). 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

An example to keep in mind:

let dict: [String : String] = ...
if dict["key"] == "value" { // String? == String
  // Do something
}

If I understand correctly, when the proposal is accepted, you'd need to do something like:

if let value = dict["key"], value == "value" { }
-- OR --
if dict["key"] == Optional("value") { }

It's not an end of the world, but makes life a bit more difficult and such usecase should be kept in mind.

Yes, Jacob also pointed this out.

Sometime later today I will push out an updated proposal that calls this out, and also discusses the overloads for equality and identity comparisons where one side is optional. I want to take another quick look at some of the changes I had to make to projects I looked at before I do so.

Mark

···

On Jul 12, 2016, at 12:58 AM, Charlie Monroe <charlie@charliemonroe.net> wrote:

On Jul 12, 2016, at 9:09 AM, Mark Lacey via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 11, 2016, at 11:55 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto: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 <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: Bool? "truth" table · GitHub

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&gt;\). 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

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

It might not be the end of the world, but I’d argue that it’s terrible and I’d hate it. A lot.

l8r
Sean

···

On Jul 12, 2016, at 2:58 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

An example to keep in mind:

let dict: [String : String] = ...
if dict["key"] == "value" { // String? == String
  // Do something
}

If I understand correctly, when the proposal is accepted, you'd need to do something like:

if let value = dict["key"], value == "value" { }
-- OR --
if dict["key"] == Optional("value") { }

It's not an end of the world, but makes life a bit more difficult and such usecase should be kept in mind.

Regarding the spelling of optional promotion, I think “postfix ?” could be
a solution. Notably, it already works in pattern matching (see the first
two case conditions here):

let anInt = 16
let anOpt = Optional(anInt)

switch anOpt {
case 2? : print("Deuces")
case anInt? : print("Huzzah")
default : print("Eh")
}

I propose we make ”postfix ?” be a general-purpose optionalizing operator,
which lets you write:

let anOpt = anInt? // Optional<Int>.some(anInt)
let anotherOpt = 2? // Optional<Int>.some(2)

Notably “?” would be essentially the inverse of “!”, so given the above we
would have:

anInt == anOpt!
2 == anotherOpt!

If we could write it ourselves the implementation would be simply,

postfix operator ? {}
postfix func ? <T> (value: T) -> T? { return Optional(value) }

The “?” syntax is so light that we could seriously consider removing all
implicit promotion to optionals, and just use “?”. Thus:

func takesOptionalInt(_ x: Int?) { }

takesOptionalInt(2?)
takesOptionalInt(anInt?)
takesOptionalInt(anOpt)

In general, anytime you have a value that you want to promote to an
optional, you would just put a “?” after it.

The one place I see where ambiguity can arise is optional chaining. I think
“anOpt?.someMethodOnInt()” should use optional chaining, whereas explicit
promotion followed by member access would need parentheses:
“(anOpt?).someMethodOnDoubleOptional()”.

In particular, “anInt?.something()” should probably be a syntax error
(attempting to using optional chaining on non-optional value), it should
not silently become “(anInt?).something()” — that would have to use
parentheses.

Anyway, that’s my idea: “postfix ?” for general-purpose optional wrapping.

Is this worthy of consideration?
Should it be part of the current proposal or spun off separately?
Would “postfix ?” sufficiently soften the landing to enable the elimination
of implicit optional-promotion across the board?
And is there a better way to handle its interaction with optional chaining?

Thanks,
Nevin

···

On Tue, Jul 12, 2016 at 3:58 AM, Charlie Monroe via swift-evolution < swift-evolution@swift.org> wrote:

An example to keep in mind:

let dict: [String : String] = ...
if dict["key"] == "value" { // String? == String
// Do something
}

If I understand correctly, when the proposal is accepted, you'd need to do
something like:

if let value = dict["key"], value == "value" { }
-- OR --
if dict["key"] == Optional("value") { }

It's not an end of the world, but makes life a bit more difficult and such
usecase should be kept in mind.

On Jul 12, 2016, at 9:09 AM, Mark Lacey via swift-evolution < > swift-evolution@swift.org> 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:
Bool? "truth" table · GitHub

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&gt;\). 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

_______________________________________________
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

Here's another proposal to reinstate mixed-optional versions of
==/!=/===/!==, assuming that coercion is removed:

Jacob

···

On Tue, Jul 12, 2016 at 11:29 AM, Chris Lattner <clattner@apple.com> wrote:

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

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

Thanks, LGTM, I merged and kicked it off.

-Chris

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:
Bool? "truth" table · GitHub

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&gt;\). 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

Personally I think we should just remove these optional-taking variants of the comparison operators. Does anyone agree/disagree?

I believe that a well-defined ordering of optionals and non-optionals is required in order to allow sorting an array of optionals.

You can argue about how useful this is, but it seems like it would be important to support this for generic algorithms.

Having said that, it also seems entirely reasonable (and safer) to disallow comparison of an optional with a non-optional value when done explicitly in code (e.g. x < y where one is a known optional), and require an explicit cast of the other operand to an optional in order to allow this to compile.

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were removed, we might want to add (T, T?) and (T?, T) versions. Are there any other operators that would be affected by your proposal? If not, removing the optional </<=/>/>= would obviate the need to remove coercion.

I haven’t attempted to enumerate all affected operators. One that I’ve run into with very strange behavior today is ?? which currently accepts non-optional values on the left-hand side due coercion, so e.g.:
  print(0 ?? 1)
will silently compile and print ‘0’ today.

Mark

···

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

Jacob

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

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

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

My opinion:
- We need to remove T -> T? promotion from operators for a whole lot of reasons. People are frequently surprised by the behavior of the ?? operator promoting the LHS to optional, for example. There are a ton of “bugs” that people file that are related to issues like that.
- We don’t have conditional conformances, so Optional cannot conditionally conform to Equatable and Comparable in Swift 3. In a later release, we can consider whether adding them is a good idea.
- We currently support equatable comparing an arbitrary optional to nil (one in which T is not necessarily Equatable), which I think is useful to keep around.
- If we allow that, then it makes sense to allow == and != operators for optionals where T is Equatable, even though the optional itself cannot conditionally conform to Equatable. The “surprising” aspect of equatable comparison doing promotions will have been removed.

The questionable piece is what to do with </<=/>/>=. I would lean towards removing them in Swift 3 simply because it is easier to "remove now, but add them back later" if they really are important. The argument for keeping them is that the surprising aspect will be solved by removing the first promotion - "42 > nil” will cease to type-check, so they may not actually be harmful anymore.

-Chris

···

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

Personally I think we should just remove these optional-taking variants of the comparison operators. Does anyone agree/disagree?

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were removed, we might want to add (T, T?) and (T?, T) versions. Are there any other operators that would be affected by your proposal? If not, removing the optional </<=/>/>= would obviate the need to remove coercion.

Yup, I too would prefer removing the functions over removing coercion.

···

On Mon, Jul 11, 2016 at 18:57 Jacob Bandes-Storch via swift-evolution < swift-evolution@swift.org> wrote:

Personally I think we should just remove these optional-taking variants of
the comparison operators. Does anyone agree/disagree?

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were
removed, we might want to add (T, T?) and (T?, T) versions. Are there any
other operators that would be affected by your proposal? If not, removing
the optional </<=/>/>= would obviate the need to remove coercion.

Jacob

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

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

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

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

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.

Sure, I mean uncommon in the sense that in the projects I’ve looked at I’m
seeing them perhaps once every 1,000-2,000 lines of commented code, not
uncommon in the sense that you will almost never see them in practice. I’m
sure for some projects it’s going to be much more often than others.

Mark

Does this really need to be a separate proposal? I mean, implicit in your
proposal is special casing the assignment operator to do the same thing
(conceptually, at least). Otherwise, let `y = 1, x: Int? = y` wouldn't work
anymore, right? So it'd probably be in scope to say that those scenarios in
which coercion currently makes sense would be preserved by the addition of
the appropriate overloads concomitant with removal of coercion generally.

···

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

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

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:
Bool? "truth" table · GitHub

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&gt;\). 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

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

I've thought of this before, too, and I agree that it's light enough it
could probably replace implicit promotion. That said, I'm not convinced
we'd really want to remove implicit promotion everywhere.

I'd also be concerned that "postfix ?" is becoming too overloaded — it's
already used in optional chaining (where it sort of "removes" a layer of
optionality), and it's the "optional pattern" for case statements...this
idea would see it used with non-optional values being passed to optional
parameters, and there's another thread started recently which (although it
seems unlikely to happen in the near future) would see it used with
optional values being passed to non-optional parameters. "postfix ?" just
becomes the "solve all my problems" operator, and I'm pretty sure
readability would suffer for it.

Jacob

···

On Tue, Jul 12, 2016 at 8:33 AM, Nevin Brackett-Rozinsky via swift-evolution <swift-evolution@swift.org> wrote:

Regarding the spelling of optional promotion, I think “postfix ?” could be
a solution. Notably, it already works in pattern matching (see the first
two case conditions here):

let anInt = 16
let anOpt = Optional(anInt)

switch anOpt {
case 2? : print("Deuces")
case anInt? : print("Huzzah")
default : print("Eh")
}

I propose we make ”postfix ?” be a general-purpose optionalizing operator,
which lets you write:

let anOpt = anInt? // Optional<Int>.some(anInt)
let anotherOpt = 2? // Optional<Int>.some(2)

Notably “?” would be essentially the inverse of “!”, so given the above we
would have:

anInt == anOpt!
2 == anotherOpt!

If we could write it ourselves the implementation would be simply,

postfix operator ? {}
postfix func ? <T> (value: T) -> T? { return Optional(value) }

The “?” syntax is so light that we could seriously consider removing all
implicit promotion to optionals, and just use “?”. Thus:

func takesOptionalInt(_ x: Int?) { }

takesOptionalInt(2?)
takesOptionalInt(anInt?)
takesOptionalInt(anOpt)

In general, anytime you have a value that you want to promote to an
optional, you would just put a “?” after it.

The one place I see where ambiguity can arise is optional chaining. I
think “anOpt?.someMethodOnInt()” should use optional chaining, whereas
explicit promotion followed by member access would need parentheses:
“(anOpt?).someMethodOnDoubleOptional()”.

In particular, “anInt?.something()” should probably be a syntax error
(attempting to using optional chaining on non-optional value), it should
not silently become “(anInt?).something()” — that would have to use
parentheses.

Anyway, that’s my idea: “postfix ?” for general-purpose optional wrapping.

Is this worthy of consideration?
Should it be part of the current proposal or spun off separately?
Would “postfix ?” sufficiently soften the landing to enable the
elimination of implicit optional-promotion across the board?
And is there a better way to handle its interaction with optional chaining?

Thanks,
Nevin

On Tue, Jul 12, 2016 at 3:58 AM, Charlie Monroe via swift-evolution < > swift-evolution@swift.org> wrote:

An example to keep in mind:

let dict: [String : String] = ...
if dict["key"] == "value" { // String? == String
// Do something
}

If I understand correctly, when the proposal is accepted, you'd need to
do something like:

if let value = dict["key"], value == "value" { }
-- OR --
if dict["key"] == Optional("value") { }

It's not an end of the world, but makes life a bit more difficult and
such usecase should be kept in mind.

On Jul 12, 2016, at 9:09 AM, Mark Lacey via swift-evolution < >> swift-evolution@swift.org> 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:
Bool? "truth" table · GitHub

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&gt;\). 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

_______________________________________________
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

Yup, I too would prefer removing the functions over removing coercion.

Hi Xiaodi,

Is there a reason you think the coercion is important to keep?

I see these as somewhat orthogonal issues (allowing or disallowing coercion vs. keeping or removing certain operators that take optionals or for that matter changing the defined behavior in the case of nil operands mixed with non-nil operands).

Mark

···

On Jul 11, 2016, at 4:59 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, Jul 11, 2016 at 18:57 Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Personally I think we should just remove these optional-taking variants of the comparison operators. Does anyone agree/disagree?

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were removed, we might want to add (T, T?) and (T?, T) versions. Are there any other operators that would be affected by your proposal? If not, removing the optional </<=/>/>= would obviate the need to remove coercion.

Jacob

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

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

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

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

Yup, I too would prefer removing the functions over removing coercion.

Hi Xiaodi,

Is there a reason you think the coercion is important to keep?

I see these as somewhat orthogonal issues (allowing or disallowing
coercion vs. keeping or removing certain operators that take optionals or
for that matter changing the defined behavior in the case of nil operands
mixed with non-nil operands).

Hypothetically, if the </<=/>/>= operators taking optionals were removed,
coercion would still be useful for ==(T?, T?) and !=(T?, T?).

But, you make a good point about ?? — it probably shouldn't be allowed to
pass a non-optional value on the left-hand side. That's enough evidence for
me to support removing coercion regardless of what happens to these
comparison operators.

···

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

On Jul 11, 2016, at 4:59 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

Mark

On Mon, Jul 11, 2016 at 18:57 Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

Personally I think we should just remove these optional-taking variants
of the comparison operators. Does anyone agree/disagree?

It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion
were removed, we might want to add (T, T?) and (T?, T) versions. Are there
any other operators that would be affected by your proposal? If not,
removing the optional </<=/>/>= would obviate the need to remove coercion.

Jacob

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

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

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

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

Personally I think we should just remove these optional-taking variants of
the comparison operators. Does anyone agree/disagree?

I believe that a well-defined ordering of optionals and non-optionals is
required in order to allow sorting an array of optionals.

You can argue about how useful this is, but it seems like it would be
important to support this for generic algorithms.

I'd be curious whether anyone can come up with a good example of why this
would be useful. Optional itself isn't Comparable (the generics features
required for that don't exist yet), so I don't think there's any way to use
this in generic code without explicitly handling the values as being
Optional, and so you might as well be required to unwrap them.

Having said that, it also seems entirely reasonable (and safer) to
disallow comparison of an optional with a non-optional value when done
explicitly in code (e.g. x < y where one is a known optional), and require
an explicit cast of the other operand to an optional in order to allow this
to compile.

Just to re-iterate my above paragraph (trying to convince myself), I think
that today the operands are *always* "known optional" or "known
non-optional", so there isn't really a way to distinguish between these
cases.

···

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

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

Yes, I agree that this should work in principle. The problem with this argument (in Swift 3) is that Optional itself can’t conform to comparable, because that requires conditional conformances. You have to use the closure-taking form of sort, at which point, using a more verbose way to compare the optional isn’t completely terrible.

-Chris

···

On Jul 11, 2016, at 5:29 PM, Mark Lacey via swift-evolution <swift-evolution@swift.org> wrote:

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

Personally I think we should just remove these optional-taking variants of the comparison operators. Does anyone agree/disagree?

I believe that a well-defined ordering of optionals and non-optionals is required in order to allow sorting an array of optionals.

> Personally I think we should just remove these optional-taking variants
of the comparison operators. Does anyone agree/disagree?
>
> It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion
were removed, we might want to add (T, T?) and (T?, T) versions. Are there
any other operators that would be affected by your proposal? If not,
removing the optional </<=/>/>= would obviate the need to remove coercion.

My opinion:
- We need to remove T -> T? promotion from operators for a whole lot of
reasons. People are frequently surprised by the behavior of the ??
operator promoting the LHS to optional, for example. There are a ton of
“bugs” that people file that are related to issues like that.

Thinking about this a bit more, couldn't the same class of "gotcha" happen
with regular functions, too? Why should this be changed for operators
specifically?

Maybe it makes more sense to have some kind of "@noncoercing" parameter, so
that coercion can still take place, but operator could be defined as `func
??<T>(lhs: @noncoercing T?, rhs: T?)`

···

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

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

- We don’t have conditional conformances, so Optional cannot
conditionally conform to Equatable and Comparable in Swift 3. In a later
release, we can consider whether adding them is a good idea.
- We currently support equatable comparing an arbitrary optional to nil
(one in which T is not necessarily Equatable), which I think is useful to
keep around.
- If we allow that, then it makes sense to allow == and != operators for
optionals where T is Equatable, even though the optional itself cannot
conditionally conform to Equatable. The “surprising” aspect of equatable
comparison doing promotions will have been removed.

The questionable piece is what to do with </<=/>/>=. I would lean towards
removing them in Swift 3 simply because it is easier to "remove now, but
add them back later" if they really are important. The argument for
keeping them is that the surprising aspect will be solved by removing the
first promotion - "42 > nil” will cease to type-check, so they may not
actually be harmful anymore.

-Chris

> Personally I think we should just remove these optional-taking variants
of the comparison operators. Does anyone agree/disagree?
>
> It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion
were removed, we might want to add (T, T?) and (T?, T) versions. Are there
any other operators that would be affected by your proposal? If not,
removing the optional </<=/>/>= would obviate the need to remove coercion.

My opinion:
- We need to remove T -> T? promotion from operators for a whole lot of
reasons. People are frequently surprised by the behavior of the ??
operator promoting the LHS to optional, for example. There are a ton of
“bugs” that people file that are related to issues like that.

Thinking about this a bit more, couldn't the same class of "gotcha" happen
with regular functions, too? Why should this be changed for operators
specifically?

You've articulated here the gist of my thinking, probably better than I
could. Taken narrowly, it's clear that coercion + these particular
functions leads to undesirable effects. But more generally, operators are
just a different spelling for functions, and since I've had occasion to
find this coercion behavior useful in calling functions, I can think of no
principled reason why operators could not be similarly make profitable use
of it (in particular circumstances). The flip side is, there are bound to
be scenarios in which coercion with regular functions would be undesirable
as well.

Maybe it makes more sense to have some kind of "@noncoercing" parameter, so

···

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

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

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

that coercion can still take place, but operator could be defined as `func
??<T>(lhs: @noncoercing T?, rhs: T?)`

- We don’t have conditional conformances, so Optional cannot
conditionally conform to Equatable and Comparable in Swift 3. In a later
release, we can consider whether adding them is a good idea.
- We currently support equatable comparing an arbitrary optional to nil
(one in which T is not necessarily Equatable), which I think is useful to
keep around.
- If we allow that, then it makes sense to allow == and != operators for
optionals where T is Equatable, even though the optional itself cannot
conditionally conform to Equatable. The “surprising” aspect of equatable
comparison doing promotions will have been removed.

The questionable piece is what to do with </<=/>/>=. I would lean
towards removing them in Swift 3 simply because it is easier to "remove
now, but add them back later" if they really are important. The argument
for keeping them is that the surprising aspect will be solved by removing
the first promotion - "42 > nil” will cease to type-check, so they may not
actually be harmful anymore.

-Chris

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

> Personally I think we should just remove these optional-taking variants of the comparison operators. Does anyone agree/disagree?
>
> It does make sense to keep ==(T?, T?) and !=(T?, T?), and if coercion were removed, we might want to add (T, T?) and (T?, T) versions. Are there any other operators that would be affected by your proposal? If not, removing the optional </<=/>/>= would obviate the need to remove coercion.

My opinion:
- We need to remove T -> T? promotion from operators for a whole lot of reasons. People are frequently surprised by the behavior of the ?? operator promoting the LHS to optional, for example. There are a ton of “bugs” that people file that are related to issues like that.

Thinking about this a bit more, couldn't the same class of "gotcha" happen with regular functions, too? Why should this be changed for operators specifically?

This occurred to me when I was considering this over the weekend, but operators are already quite special. You can specify whether they are infix, prefix, or postfix, and assign a precedence. They are used without any special syntax to “apply” them, unlike normal functions which are applied with (…). I would go as far as saying that most (non-PL, non-compiler implementor) people wouldn’t consider operators and normal functions to be very closely related at all.

We clearly wouldn’t want to remove the coercion for the regular functions because it’s extremely convenient. I know you’re not suggesting doing so, I’m just pointing out that if we made things uniform we’d clearly have to keep the coercion by default.

Maybe it makes more sense to have some kind of "@noncoercing" parameter, so that coercion can still take place, but operator could be defined as `func ??<T>(lhs: @noncoercing T?, rhs: T?)`

I’m not sure it’s really worth adding another attribute just for this purpose.

Mark

···

On Jul 11, 2016, at 6:02 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:
On Mon, Jul 11, 2016 at 5:58 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:
On Jul 11, 2016, at 4:56 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

- We don’t have conditional conformances, so Optional cannot conditionally conform to Equatable and Comparable in Swift 3. In a later release, we can consider whether adding them is a good idea.
- We currently support equatable comparing an arbitrary optional to nil (one in which T is not necessarily Equatable), which I think is useful to keep around.
- If we allow that, then it makes sense to allow == and != operators for optionals where T is Equatable, even though the optional itself cannot conditionally conform to Equatable. The “surprising” aspect of equatable comparison doing promotions will have been removed.

The questionable piece is what to do with </<=/>/>=. I would lean towards removing them in Swift 3 simply because it is easier to "remove now, but add them back later" if they really are important. The argument for keeping them is that the surprising aspect will be solved by removing the first promotion - "42 > nil” will cease to type-check, so they may not actually be harmful anymore.

-Chris