[swift-evolution] ? suffix for <, >, <=, >= comparisons with optionals to prevent subtle bugs

Al Skipp al_skipp at fastmail.fm
Wed Dec 9 12:30:34 CST 2015


It’s curious that your example won’t compile (didn’t when I tried it in a Playground), however the following does:

let ps = peeps.filter { $0.pet.map { pet in pet.age < 6 } ?? false }


My perspective is still that the issue isn’t with Optionals being comparable, but in certain edge cases the auto wrapping of non Optionals is what causes the confusion, as it’s not obvious that the comparison is between Optionals.

Regarding the default semantics, I’d say the semantics of Optional comparison is pretty reasonable and fits with:

"" < "abc" == true
[] < [1,2,3] == true
.None < .Some(0) == true


Al



> On 9 Dec 2015, at 17:44, thorsten at portableinnovations.de wrote:
> 
> That's why I would prefer that optionals are not comparable by default.
> 
> Then I would simply have to write
> 
> let ps = peeps.filter { $0.pet?.age.map { age in age < 6 } ?? false }
> 
> making the intended semantics explicit, which is necessary IMHO because there is no default semantics for comparing nil with something else (depending on my specific use case I might have chosen to return true in the nil case).
> 
> -Thorsten 
> 
> 
> Am 09.12.2015 um 13:03 schrieb Al Skipp via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>>:
> 
>> I don’t have a problem with Optionals being comparable, but I do see the potential for bugs occurring as Swift automatically wraps values as Optionals when required. Not sure what the solution would be here, other than to make the wrapping of values explicit?
>> 
>> Here’s an example of when automatic Optional wrapping can cause unexpected results:
>> 
>> struct Pet {
>>   let age: Int
>> }
>> 
>> struct Person {
>>   let name: String
>>   let pet: Pet?
>> }
>> 
>> let peeps = [
>>   Person(name: "Fred", pet: Pet(age: 5)),
>>   Person(name: "Jill", pet: .None), // no pet here
>>   Person(name: "Burt", pet: Pet(age: 10)),
>> ]
>> 
>> let ps = peeps.filter { $0.pet?.age < 6 }
>> 
>> ps == [Fred, Jill] // if you don’t own a pet, your non-existent pet is considered to be younger than any actual pet  🐶
>> 
>> 
>> If the Optional wrapping of ‘6’ in the comparison had to be explicit, then the result wouldn't be so unexpected.
>> 
>> Al
>> 
>> 
>>> On 9 Dec 2015, at 11:31, Lucas Derraugh <lucas.derraugh at me.com <mailto:lucas.derraugh at me.com>> wrote:
>>> 
>>> This is related to a question I asked on SO a while back: http://stackoverflow.com/questions/26172911/swift-nil-has-a-numeric-value <http://stackoverflow.com/questions/26172911/swift-nil-has-a-numeric-value>
>>> 
>>> Seems that many others have had confusion with the same problem, and it can sneak into your code without being aware of it. The simple case that I ran into was comparing an Optional Int to an Int. It is a very subtle bug and one that I don’t think should be allowed to occur. To me the intent isn't clear in this situation. I don’t think nil should be considered true or false if compared against. The only alternative I can think of is if comparing anything to a nil value, the result would be false; this would probably still lead to unexpected behavior though.
>>> 
>>> Lucas Derraugh
>>> lucas.derraugh at me.com <mailto:lucas.derraugh at me.com>
>>> 607-793-3517	
>>> 
>>> On December 9, 2015 at 6:10:40 AM, Al Skipp via swift-evolution (swift-evolution at swift.org <mailto:swift-evolution at swift.org>) wrote:
>>> 
>>>>> To me it seems logical that comparing Optional<Int> with Int (or another
>>>>> Optional<Int>), if it's allowed at all, should return Optional<Bool>. Since
>>>>> conditional statements only accept Bool, the user is forced to handle the
>>>>> nil case explicitly.
>>>> I disagree that comparing Optional values should have a return value of Optional<Bool>.
>>>> If the following were to be true:
>>>> 
>>>> .None < .Some(0) == .None
>>>> 
>>>> Then logically, this would be too:
>>>> 
>>>> [] < [1,2,3] == []
>>>> 
>>>> I think most people would agree that the correct result to that comparison should be ‘true’, not [].
>>>> 
>>>> When comparing ‘container’ types I think it’s important to have a simple Bool result, otherwise things get very peculiar (conceptually the Optional type is really just a container with a maximum count of 1).
>>>>  _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151209/fcf09343/attachment.html>


More information about the swift-evolution mailing list