bool_not
Adding inherent .not()
method to bool
type that matches the behavior of logical negation operation !bool
.
A thread in internal methods proposing adding "is_not_empty() as an alternative for !is_empty()".
One idea that people often suggest is adding an inherent .not()
method directly on bool
type [1][2].
There are some complaints about the use of !
sigil as the logical negation operator:
!
is easy to miss. People often have to double look at calls like if vec.is_empty() {}
to be sure they don't miss the !
sigil. This might slow down reading code speed.!
requires extra care when used in long expressions like !requests.params.config.key.value.filter(|o| ...).map(|o| ...).is_empty()
.Adding .not()
method to bool
type would allow people to use vec.is_empty().not()
.
Now the logical negation operation is hard to miss.
People don't need to importing trait core::ops::Not
for every module they would like to use this method.
The builtin boolean type bool
now contains an inherent method not()
that represents logical negation operation.
Now people are recommended to use bool.not()
instead of !bool
.
The RFC is very easy to implemented:
#[lang = "bool"]
impl bool {
pub fn not(self) -> bool {
!self
}
}
That would allow us to use <boolean expression>.not()
directly without importing Not
trait.
For example: Instead of !vec.is_empty()
, not we go with vec.is_empty().not()
.
vec.is_empty().not()
is readable, but some people may find them funny[3].
The inherent bool::not()
method should not interact badly with T: Not
as proved here: https://rust.godbolt.org/z/WMK3ss. Compiler should prefer inherent .not
method over .not
from core::ops::Not
trait.
Why should we not do this?
!
sigil.
Now they have to transit over .not()
method.!
(1 character) and now .not()
(5 characters).Adding .not()
method directly to bool
requires very little changes (3 lines of code excluding documentation) to the standard library.
It would solve the readability problem caused by using !
in boolean expressions.
People continue to use the !
sigil, which might cause subtle bugs because of missing/forgetting to notice that tiny sigil.
People that prefer to use .not()
method have to import core::ops::Not
in every module they want to use it.
false == boolean
or boolean != true
instead.vec.is_empty()
, we could add Vec::not_empty()
or Vec::is_not_empty()
or Vec::has_items()
and use that instead. Howevery this again requires care about !vec.is_not_empty()
calls and the likes.!
, for example ! true
. This is also a good alternative. However, this might be prior art for other space-sensitive syntax additions in the future.core::ops::Not
be a part of the prelude. This is actually quite a good alternative. However, this will allow using .not
more than just on bool
type, which might cause more problems with existing code.~
as alternative for !
: ~true
. ~
More readable than !
. However, ~
is not very popular as the logical negation operator in other programming languages either.true.! == !true == false
. But this might be the same as using true.not()
directly..not!
macro. Might be easier by just using true.not()
. This also requires adding postfix macro support to the language.not
function. Something like core::ops::not(true)
. This requires people to import that function to conveniently use it..nicht()
or .sike()
instead of .not()
(suggested by CAD97).not
as a prefix keyword in new edition. This might cause a lot more churns than this RFC. Also if not a && b
is not quite clear if not
covers both a && b
or just a
.¬
sigil (used in logic languages), but the preferred trend is to not adding more sigils.
Another disadvantage is that this symbol is not easy to type on normal keyboards.unless
keyword. This might really harm code readability [4][5].The Rust language team doesn't want to accept new sigils for features.
Adding bool::not()
is not against that goal/trend.
Here is the table for the syntax used for logical negation in some programming languages[6]:
Language | Sigil/keyword | Example |
---|---|---|
ALGOL 68 | NOT (or ¬ [7]) |
NOT true (¬ true ) |
APL | ~ |
~0 |
C / C++ / C# / D / Go / Java / Swift / Zig / PHP / JavaScript / Scala | ! |
!true |
Common Lisp | not |
not a |
Python / Eiffel / Haskell | not |
not True |
Ocaml / Erlang | not |
not true |
Perl / Raku | not or ! |
not true or !true |
Pascal | not |
not(true) |
Ruby | ! |
!a |
Scheme | not |
not a |
PL/I | ^ |
^'0'b |
Prolog | \+ |
\+false |
Seed7 | not |
not TRUE |
Smalltalk | not |
true not |
Visual Basic .NET | Not |
Not True |
We could add a new keyword not
(for example not true
). But adding a new keyword requires heavier changes in compiler and language syntax.
It also requires new addition to take benefits of improving readability.
Old Rust editions have to continue to use !
syntax.
This leaves us with the options of an inherent .not
method on the boolean type, which all editions could start to use.
Note that there is .await
(in future.await
) used as a postfix keyword instead of await Task
in C#.
bool::not()
actually interact soundly with Not
trait ?!bool
and guide people to use bool.not()
instead?!bool
and guide people to use bool.not()
instead.https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/4 ↩︎
https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/8 ↩︎
https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/4?u=lzutao ↩︎
https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/111 ↩︎
https://internals.rust-lang.org/t/the-is-not-empty-method-as-more-clearly-alternative-for-is-empty/10612/26?u=lzutao ↩︎
Information gathered in Wiki and Rosettacode pages: https://rosettacode.org/wiki/Logical_operations and https://rosettacode.org/wiki/Boolean_values ↩︎
For a European 8 bit/byte character set, for example, "ALCOR" or "GOST ¢" ↩︎