[Proposal] Add property for negation to Bool

  • First, I apologize for seeming patronizing in the previous post — I definitely see how it can come across that way. That was not my intent; I just want to debate the design of standard library. I agree that extending libraries like the standard library can be very powerful; I just think extensions should depend on the project so that we can avoid language dialects. I also assumed that you found the prefix ! operator confusing, but now I see that you do understand it and just prefer .not syntax.
  • I mentioned reverse polish notation because @tera mentioned it and I was responding to him.
Speaking of @tera…
  • I think that using ~ for both the logical and bitwise NOT operators could actually be confusing. There are many people who are aware of the logical operators, yet unaware of the bitwise operators. If one of these users were to encounter a bitwise operator in someone else’s code, they would know something was different because it’s different than the logical operator. Having the same operator would remove this visual indicator.
  • Chaining properties and methods is similar to RPN, but the rest of the language isn’t RPN — even the built-in arithmetic operators are infix. This doesn’t mean RPN isn’t useful, it just means that Swift isn’t the right fit for it.
  • I think it’s actually pretty interesting to think about how a modern stack-oriented programming language would look — maybe something like this?
x: Int, y: Int -> isMultiple: Bool {  //  func isMultiple(_ x: Int, _ y: Int) -> Bool {
                                      //      
    y 0 == {                          //      if y == 0 {
        x 0 == return                 //          return x == 0
    } if                              //      }
                                      //      
    y -1 == {                         //      if y == -1 {
        true return                   //          return true
    } if                              //      }
                                      //      
    x y % 0 == return                 //      return x % y == 0
                                      //      
} func                                //  }
                                      //  
result let 4 2 isMultiple =           //  let result = isMultiple(4, 2)
                                      //  
complementOfResult let result ! =     //  let complementOfResult = !result

It is a bit esoteric, but I do kind of like it. However, it’s still not as expressive as Swift’s 4.isMultiple(of: 2).

  • I know about if/switch expressions — I just don’t think they’re better than what we have now. I don’t think the ternary conditional operator is much harder to learn than the other operators, and changing the ternary conditional operator and making if/switch into expressions are both on the commonly rejected proposals list. I don’t really want to rehash this debate though, so I’ll just link to this post from Chris Lattner that sums up my thoughts and move on.
  • I said that we shouldn’t assume every Swift programmer to be a C programmer in my last post, but it’s also important to recognize that Swift doesn’t live in a bubble: many popular programming languages are influenced by C and use the ! operator for negation. We should only deviate from this common pattern if there’s a compelling-enough reason to justify the change.
  • I’m not doubting that you’ve met people who prefer == false over !; I just can’t find anything related to this debate on the web. If you can show me an example, that would be great (but you don’t need to — it’s hard to search for “== false” because search engines ignore the equals signs).
  • In the case of an optional boolean, if !isBlue also forces you to deal with the optional, the same way that if isBlue?.not does. I would personally write this using the Optional.map method as if isBlue.map(!) ?? false. I don’t think either syntax is super expressive, but I don’t encounter optional booleans very often anyway.
  • I don’t consider extracting to constants an anti-pattern — in fact, extracting logic to a constant can be clearer and more performant than the alternative. For example, it is used to avoid repeating expensive operations:
let sequenceCount = sequence.count
// this could be an expensive, O(n) operation, so you don’t want to repeat this more than once

Also, consider this code (I know there are better ways to do this, I just don’t want a super-complex example):

for i in teams.indices {
    for j in teams[i].people.indices {
        let person = teams[i].people[j]
        if !person.hasPeanutAllergy {
            give(TrailMix(), to: person)
        }
    }
}

In the example, we don’t really care how we accessed the person instance — when we use the person constant, we only need to check if they have a peanut allergy and use them in the give function — there’s no need to include how it was derived in its name. This manner of hiding unnecessary implementation details aligns with the principle of abstraction that protocol-oriented programming (as well as many other areas in computer science) is based on.

  • I agree that Swift’s similarity to written English is one of my favorite things about the language. However, when you associate ! with “not”, it’s actually closer to English than putting not at the end: “if the person does not have a peanut allergy …” vs “if the person has a peanut allergy not …”.

With all that being said, I think this discussion has gone on past its point of diminishing returns. I don’t think that anyone reading this will change their minds at this point and we seem to be getting off-topic frequently, so I think we should just agree to disagree: some people think .not is better, while other people prefer the prefix ! operator.