I'm a very strong +1 on a .negated property, since I personally avoid the ! operator as much as possible (both prefix and postfix versions): it's a tiny thing and is easy to miss while scanning code and takes extra mental translation to figure out what it's doing. That being said, being able to use it in key paths would definitely be Nice To Have™, along with a .negated property.
The ! operator would be more useful than a negated bool property as it would work with any method that returns a Bool. It would work to negate methods on sequence like contains as well as shown in this post. The only draw back is that it might slow down the compile time.
That's very cool, and useful. The only downside is that this operator can't output a KeyPath. For that I think you do need to add a .negated property, at least a private one.
It's nice to see this topic show up every once in a while. I 100% support this, and add a .not extension to Bool in all my projects. To me, the ! prefix for negation is historical baggage that should be dropped. Also, this doesn't clash with the commonly rejected proposals, because it's not about replacing a prefix operator - currently defined with an operator-friendly character - with an identifier based on letters (like not this() instead of !this()) but it's about adding a computed property to Bool.
I don't see a compelling reason for why the ! operator should be deprecated or why it would be considered "historical baggage". Comparing these two syntaxes,
if ¬somePredicate() { ... }
if !somePredicate() { ... }
I actually find ¬ to be slightly less noticeable than !. And adding a toggled/negated property makes the code less readable. Instead of reading as "if not predicate", it would read as "if predicate toggled/negated" as has been noted earlier in the thread.
I've also never encountered a situation where I've had to scan my code for the prefix ! operator — I just use the operator when I need the Bool's reverse. There may be some mental translation when you start using Swift, but it goes away once you've used it for a while. And the ! operator can reduce a lot of clutter compared to an instance property, which I think makes the tradeoff worth it.
The ~ operator is already the bitwise NOT operator for integers. Not only would this be confusing, but it would also probably take more time for the compiler to resolve the overload. And using ¬ as an operator would be needlessly hard to type since most keyboards don't have a ¬ key and the programmer would have to memorize the keyboard equivalent (and if they're on Windows, there might not even be an equivalent because a user might not have a number pad, which I believe is required for special character input on American Windows keyboards). It would also be more prone to mojibake when code is shared on the web.
Most of Swift's operators are the same as other C-family languages. Making ! an exception to this pattern would make switching between languages or copying code from another language more prone to errors. The commonly rejected proposals document states that Swift only deviates from C syntax if a feature is harmful or adds needless clutter. The prefix ! operator doesn't seem to fit into either category — it even reduces the clutter that an instance property would have.
... many good reasons. and i agree - is too late for swift to change here!
collapsed is a justification for "bool ! is a historical baggage" claim.
"if we started swift today from scratch would we use the same syntax for optional unwrapping and for boolean negation" - i'd say - definitely not. time and again i sanitise my code to reduce the number of unsafe optional unwraps and every time i am searching for "!" i hate this unfortunate design choice made in 1970s and carried over unchanged to swift (some would argue that this is the optional unwrap usage of "!" that is to blame)
there is nothing wrong with if some["long"].expression["here"].blah.not { ... }
it is less "engish" but very reasonable still and arguably easier to grasp as it involves "left to right mental scanning with no need to remember that the end expression needs to be inverted" which is very reasonable for long expressions. (obviously, i am a big fan of reverse polish notation, if you haven't figured yet.)
the previous bullet point notwithstanding, most programming languages with few notable exceptions use prefix form of boolean negation, to further screw us, "reverse polish notation lovers".
¬ symbol is indeed not keyboard friendly, also being a prefix it shares the "drawbacks" of other prefix alternatives (be them !expr or "not expr" or anything else). there are precedents though.
that "~ operator is already the bitwise NOT operator for integers" doesn't mean it can't be theoretically used for bools (the same way we don't use a separate plus operator for ints and doubles). yes, ~ is also a prefix operator but let's ignore this aspect for now. note, that in reality ~ and other bitwise operators are used extremely rare in swift.
"Most of Swift's operators are the same as other C-family languages" that's the only "good" reason why it is what it is. that's why some folks call it "historical baggage". remember, swift is supposed to be Objective-C without the baggage of C.
What we should have is the ability to explicitly call operator methods. A method of differentiating between prefix and postfix operators would be necessary (maybe some form of cast, if that’s part of the type?), but it would otherwise be straightforward to have boolean.! be equivalent to !boolean. A special token might be needed to distinguish operators that begin with a ..
At any rate, I don’t believe we should have redundant properties in the standard library at all. If you really want something like this, add this to relevant files:
Just to elaborate a little bit more, I've seen time and time again developers working in different languages and contexts to discourage the usage of the ! prefix operator for negation, preferring == false at the end of a boolean expression because it's clearer and reads better. There's no way around this, ! in prefix position only works for constants:
let isFooBlue = some.nested[data].structure(common: inSwiftCode).isBlue
if !isFooBlue { ... } // ok I guess
I'd argue that ¬ is better – especially in Swift where ! has a very, very specific meaning, that's more in line with the "urgency" suggested by the symbol itself – but on the other hand we're using the classic && and || symbols for ∧ and ∨, which are even worse to reach, at least on my keyboard.
To me, the best, simplest, easiest on the eyes, more readable and understandable solution, even from a total beginner (let's not assume that a Swift beginner will know C or a C-family language please), would be to add a computed property to Bool:
if some.nested[data].structure(common: inSwiftCode).isBlue.negated { ... } // good
if some.nested[data].structure(common: inSwiftCode).isBlue.isFalse { ... } // better
if some.nested[data].structure(common: inSwiftCode).isBlue.not { ... } // best
There are some good points about how the prefix ! operator is a bit weird, but I don't think they cause much harm to well-written Swift code.
I believe that whenever a programmer uses the force-unwrap operator, it should be considered good practice to write a comment explaining the assumptions they are making. This helps offset the lost expressiveness that comes with force-unwrapping and makes crashes easier to diagnose.
Swift does not use reverse polish notation anywhere else in the language, so it would be weird to only have it for getting the complement of a Bool. I think it’s likely that most Swift programmers have never been taught reverse polish notation, and even if they did learn it, they wouldn’t gain much from having that knowledge as they’d have no use for it. Also, reverse polish notation makes it much easier to accidentally mix up the order of operands/numbers.
However, you have to use parentheses, which negates one of the biggest benefits of RPN, and larger expressions would be harder to type-check and could lead to a compiler timeout.
There is a precedent for symbols being reused in operators with the ternary conditional operator (?:). The ternary operator reuses ? (which is typically associated with Optionals) and : (which is typically used to mean “of this type” or express an argument label). If we’re going to justify removing the logical NOT operator because ! is typically used for Optional unwrapping, we would also need to find a better alternative to the ternary conditional operator. (I realize that the ternary conditional operator can be controversial but, as far as I’m aware, nobody has yet come up with a better alternative.)
There is no precedent in Swift of reusing the same operator for a bitwise operation and a logical operation (like is being proposed with ~). And while bitwise operations are pretty rare in Swift, they are still useful and used in the implementation of many algorithms (especially ones related to cryptography).
ALGOL 68 came out one year after ASCII’s 1967 revision (which contains all the character codes we use today) and way before the first ANSI keyboard layout standard was published (ANSI X3.154-1988). While it does allow the use of some abnormal characters in certain contexts, many different computers back in those days had many different keyboard layouts depending on country, language, and manufacturer. Today, our computers are more standardized so allowing for these kinds of symbols isn’t really necessary. In fact, C++ just removed its ciso646 header in the C++20 standard.
While it’s true that Swift is meant to resemble Objective-C without the baggage of C and that we shouldn’t expect every Swift programmer to be a C programmer, I believe we should account for the many Swift programmers who also program in another C-derived language. It would have been possible to make Swift a programming language that reinvented everything and was significantly different from C (like Haskel or Lisp), but instead Swift embraces its C heritage and its familiarity to C-family programmers is one of the language’s benefits. The Swift Programming Language reference book often compares Swift with C and Objective-C — even the first paragraph in the language guide states that “many parts of Swift will be familiar from your experience of developing in C and Objective-C.”
I’ve never seen any professional developers encourage the use of == false over !. Furthermore, I wasn’t able to find any recommendations like this by searching the web or reading style guides from Google, Ray Wenderlich, and LinkedIn.
Some people have suggested that if you want a Bool.not instance method, you should just create an extension to the Bool type yourself. However, I think this should be discouraged. If every Swift programmer has their own extensions to the language that they use on every project, then your code becomes harder for other programmers to understand and collaborating with other programmers becomes a hassle as there will be a mishmash of different styles. Instead, try to stick to Swift conventions and only extend types when there is a compelling reason why your current project would benefit from it. Plus, if you give the prefix ! operator a chance, perhaps you’ll find yourself getting less confused by it.
I don’t find
if some.nested[data].structure(common: inSwiftCode).isBlue.not { ... }
any easier to read at all than
if !some.nested[data].structure(common: inSwiftCode).isBlue { ... }
. Having not at the end is inelegant (I think it’s important to note that most notations for negation use a prefix) and it doesn’t make the code any more clear to me. If you find a condition confusing, I think that extracting the condition to a constant is the best option with either syntax.
let isFooBlue = some.nested[data].structure(common: inSwiftCode).isBlue
if !isFooBlue { ... }
if isFooBlue.not { ... }
// improves clarity for both
good practices/comments are not enforced or checked.
in some projects i go into trouble and change "x!" to:
x.unwrap("comment")
along with removal of "!" in other contexts (like bool negation) i can make the sources almost completely "!" free ("var x: Type!" is a notable exception).
chaining properties/method calls itself is like reverse polish notation (so people using it without realising).
the distinction between ~ and ! was important in C, as C didn't have a bool type, bools were simulated with ints, so there had to be two different operators on int giving different results: ~0 = ffff and !0 = 0001. this baggage was carried over to swift unchanged (unfortunately imho, as there would be no confusion between ~boolValue vs ~intValue)
i actually hate explicit checks like "x == true" or "x == false", etc. i only use them with optional types, where "x = optBool == true" and "x = optBool" can possibly give different results.
yes and no... i can create my own standalone "func isOdd(Int) -> Bool" in my projects and i don't think that would be a problem for others to understand. similarly instead of a standalone function i could create a "var isOdd: Bool" as an extension to int - and it wouldn't be a problem for others to understand it either. there is no law in swift saying that one is better than another, and as the second one avoids parens and allows "reverse polish notation" usage (aka chaining) i would go for it. but of course standard / common conventions are best, hence this very discussion existence and the pursuit for some common grounds that would be accepted by most if not all.
perhaps this will help, consider a slightly different case:
if some.nested[data].structure(common: inSwiftCode).color.isWarm { ... }
vs
if isWarm(some.nested[data].structure(common: inSwiftCode).color) { ... }
vs
if isWarm some.nested[data].structure(common: inSwiftCode).color { ... }
// the last one is pseudo syntax but bear with me
would you prefer the first the second or the third? i'd prefer the first as the two related things "color" and "isWarm" are next to each other. to me there's no conceptual difference between this example and bool example above, where "isBlue" and "not" are related to each other and thus shall be close to each other.
chaining was invented precisely to eliminates extra variables...
That's a long jump from adding an extension to Bool. On the other hand, the Swift standard library has a lot of functions and computed properties that are spelled out in the past tense in order to communicate that they will return some value with added transformation.
In order to avoid (I guess) having "two ways to do the same thing", something like negated doesn't exist on numbers (only the mutating func negate()), so the solution is supposed to be adding the - prefix operator, but this, while not ideal in my opinion, is less concerning because the use cases of negated on a number are much more rare than the equivalent on Bool.
The ternary operator is another example of historical baggage, and:
it's hard to understand from beginners;
if we had an "if expression" it would be probably become the standard way to do ternary expressions because it's more readable, especially when you have multiple nested expressions (there's already some thread in the Swift forums about this).
Kotlin, for example, doesn't have a ternary operator, but you can use if as an expression, and the language is better for it.
I'm aware of all this, but it's not a good argument. Three points:
Swift already got rid of many C derivations, because it offers better ways of doing some things, or some constructs were deemed pointlessly complicated;
we should eventually stop assuming that beginner Swift programmers are familiar with C;
adding an extension to Bool in a language that really, really likes to express functionality as methods on types is hardly comparable to creating a language that's "significantly different from C (like Haskel or Lisp)".
I guess we went to different circles. I've seen them, and I've seen many more that would have preferred that but didn't use it because of a internal team style guide.
I've been programming with Swift since its very first release, and I read this as a little patronizing. I (and others) find lots of compelling reasons to add extensions to the standard library because you can frequently find "holes" that can only be identified if you tried to fill them youself and see what works and what doesn't.
An example is the fact that Sequence has a forEach method, that competes with for ... in (with important differences that make you lean towards one or the other given the situation) but there's no equivalent method ifSome on Optional (that would compete with if let, with similar differences).
Another example is the lack of an |> operator, that's extremely useful in many cases, and it's used in other languages.
The last phrase of the quote is especially patronizing. Of course I gave plenty of opportunities to the ! prefix, and I found a lot of shortcomings, especially in Swift. Another place where the ! prefix is bad is when dealing with Optional<Bool>. Suppose you have a let isBlue: Bool?, and want to check on it:
if !isBlue doesn't compile;
if !(isBlue ?? true) is hard to understand (I see true but the expression is false if isBlue is nil);
adding a new definition for prefix ! to deal with optionals will hide the logic and increase the likelihood of mistakes.
While if isBlue?.notwill force you to deal with the optional and the solution will be easier to understand, because for example if isBlue?.not ?? false clearly means that if isBool is nil, the check will not pass.
I guess I can send your advice back to you and encourage you to try and use something like Bool.not, and see if it works for you.
I do, for very obvious reasons: the second expression has the ! operator and the Bool it's applies to very far from each other, while in the first every "operator application" immediately follows the expression it's applied to, in the form of a function call.
This is, to me, a classic bad pattern when programming. This code
let isFooBlue = some.nested[data].structure(common: inSwiftCode).isBlue
if !isFooBlue { ... }
seems to make sense, but it really doesn't, because the expression some.nested[data].structure(common: inSwiftCode).isBlue contains all the information necessary (in the most expressive form) to understand what the Bool it returns means. Binding the return value of the expression to a constant doesn't improve clarity, because the constant name cannot "compress" the information contained within the expression.
In fact, what always happens is that you see the isFooBlue constant, you see the if !isFooBlue check, and you go back to the definition of isFooBlue to understand what was that about. In order to keep the information about the origin of the isFooBlue constant, it should be called something like let isSomeNestedDataStructureCommonInSwiftCodeBlue, then the prefix ! could make more sense, but the constant makes no sense in itself because it's redundant, and prefix ! would still be pretty bad in terms of readability because the proper negation for if the constant would be isSomeNestedDataStructureCommonInSwiftCodeNotBlue, which is closer to isSomeNestedDataStructureCommonInSwiftCodeBlue.not than to the prefix notation.
Swift is not C and it's based on very fundamental differences in how the code is written, in particular Swift tries to mimic "natural language" in its constructs and APIs which, in my experience, makes it enjoyable and interesting to some programmers that come from a different background, and like its approachability. ! and the like are historical baggage that should be dropped, and replaced with a better alternative for the language (not necessarily the .not computed property), that's not just based on what feels familiar to a specific group of programmers, with a specific background, that maybe having given the choice would choose something different.
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.
For the usual reasons, isBlue.map(!) is confusing, and will be especially to a beginner, due to the double meaning of ! in Swift. Solving if !isBlue in a clear way is extremely hard (I've shown that pretty clearly), while having a .not computed property is certainly easier to understand thanks also to the requirement of ?. optional chaining. I can't say much more about it, the code seems pretty self explanatory to me, and the only argument for prefix ! is really "it was like that before", that, I hope I've shown this too, is clearly not enough.
I don't think it is in general, but it becomes it when it makes the code harder to understand. I don't understand your example, that's terrible Swift code and it's not very useful as an example of prefix ! usage. The way you would probably write this in idiomatic Swift is something like
for person in teams.flatMap(\.people) where !person.hasPeanutAllergy {
give(TrailMix(), to: person)
}
in which the prefix ! operator is fine. But my example is completely different, and it's not always the case that you can find a proper name for a constant "one level higher" than the Bool. Following your example, I would need something like
let someNestedDataStructureCommonInSwiftCode = ...
if !someNestedDataStructureCommonInSwiftCode.isBlue { ... }
which is equally bad.
That's simply not always the case for data structure, and I would argue it's not even the case in your example: I need to at least understand that we're iterating "all people in all teams", thus it would be at least better to define a constant like
let allPeople = teams.flatMap(\.people)
That's not the correct analogy: it would instead be “if not the person does have a peanut allergy …” vs “if the person has a peanut allergy not …”, which is equally not ideal, but actually the first version is ambiguous, while the second is at least clear. It seems to me that you don't have much experience in using something like Bool.not in production, and how clearer it makes a lot of code.
I think there are 2 reasons why these kinds of discussions seem to be rekindled every once in a while:
most people never used (in production, for a decent amount of time) something like Bool.not, but every once in a while someone tries it and sees the advantages;
no good argument in favor of prefix ! is given other than "it was like that before", which becomes a weaker and weaker argument as time passes, especially for Swift.
While this was true in 2016, at least in my opinion, which agrees with yours, having a property for negation on bool proves to be useful in for getting values using from a root using key paths.