Can you use the XOR assignment operator ^= with booleans in Rust? That’s the question I asked on X (formerly Twitter), just to entertain you a little bit between two posts, and as an excuse to deal with some additional topics.
So without further ado, here is the result of this first quiz:
Quick Quizz: Can you use the XOR assignment operator ^= with booleans in Rust?
— Syntax Error (@SyntaxErrorFail) September 2, 2024
The right answer, as we’ll see further, is: yes, the XOR assignment operator is supported by Rust’s booleans.
As shown in the poll results, there is a majority of wrong answers. Were you among the majority or did you guess correctly? If not, don’t be disappointed, because even the smarter of artificial intelligences, with all their petaflops of compute, petabytes of data and billions of digital synapses, didn’t get this right.
LLMs on the Spot #
In my personal experience, LLMs are still surprisingly weak at coding in Rust, compared to how they deal with mainstream languages. I assume this is due to Rust still being a relatively young and niche ecosystem, so the size of the training data is comparatively much lesser than, for instance, C, Python or Java.
Even though this doesn’t disqualify Rust – at all – as a good choice for a programming language, my advice would be to bear that in mind before doing something crazy, like, for instance, rushing into a solopreneur endeavour on a full-stack Rust project :)
Don’t get me wrong, their help is still invaluable for Rust programming, but they must often be closely guided to the right answers, and the solutions they propose should definitely be taken with a grain of skepticism, and carefully scrutinised.
In this case, if some of the quiz participants were a bit lazy, and merely copy-pasted the quiz question into Claude or ChatGPT, there is a good chance they gave the wrong answer (which was my initial intent, hehehe!).
Even more interesting is that Grok 2 did answer correctly. This is a general observation of mine that Grok is already a strong contender in the LLM world. It has quickly become my preferred AI assistant for the past few weeks.
Now how could you get the right answer if you don’t know it from the top of your head?
std::ops #
The Rust language has operator overloading, which is a language feature I personally much like in certain circumstances.
It is easy to overload most of the operators for a struct by implementing the traits provided in the std::ops module of the standard library.
The +
, -
, *
, /
, to name a few, can be overloaded easily by implementing the Add, Sub, Mul and Div traits. If you are new to Rust, you may be slightly intimidated by the traits’ associated types. Well, don’t be. These are just types associated to the trait that are defined by the implementors of the trait. In the case of operator traits, they often refer to the resulting type after applying the operator (which is often Self
, as the result of applying an operator on a type often result in a value of the same type).
The XOR assignment operator ^=
can be overloaded by the BitXorAssign trait, which is defined as the “bitwise XOR assignment operator”.
One might think that booleans do not qualify for bitwise operations, but there are a few ways to verify if it is indeed the case: you can either try by yourself, read the docs and/or read the code.
Try #
First, we can simply create a temporary project and try it! But if, like I have done, you mistype the operator, you might get a false negative. It must typed ^=
, not ˆ=
!
fn main() {
let mut flag = false;
// flag ˆ= true; // Wrong
flag ^= true;
if flag {
println!("It works!");
}
}
Read the docs #
The Implementors section of the RustDoc lists all the implementors of the BitXorAssign traits in the standard library, and bool is indeed present in this list (it’s actually the first one).
Read the code #
As Rust is open source, the bravest of yours could also browse the source code of the BitXorAssign trait, which contains, right after the trait definition, the following macro statements, whose explanation definitely goes beyond the scope of this post:
macro_rules! bitxor_assign_impl {
// ...
}
bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
Why do we care anyway? #
So, Rust Booleans support the XOR assignment operator. What about it?
It is always possible to invert a boolean’s value by simply doing something like:
flag = !flag;
This is of course a matter of taste, but the XOR operator is, in my view, an elegant alternative for flipping a boolean’s value.
As a reminder in case you were distracted during the Digital Logic class, here is the table summarising the effects of the XOR operator on all possible values of two bits A and B:
A | B | A XOR B |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
As we can see:
- if
B
isfalse
,A
remains unchanged - if
B
istrue
,A
is inverted
Imagine a boolean variable light_switch
which represents the light turned on if light_switch
is true, and off if light_switch
is false, you can turn the light on and off using the ^=
operator like this:
light_switch ^= true;
Now imagine the switch should be flipped only if a certain condition condition
is true, here is what you can do:
light_switch ^= condition;
In this case, the light switch remains unchanged if the condition, which can be whatever you want, is not fulfilled.
Also note that conditionally switching the boolean using the other method described above would require an arguably uglier conditional statement such as:
if condition {
light_switch = !light_switch
}
My personal taste is to use the XOR operator or another alternative depending on what I precisely mean. If I mean to flip the boolean, I’ll use the XOR operator. Otherwise, I’ll go for another kind of assignment.
Conclusion #
Thank you for participating in the quiz and for reading this post. If you liked it, please give it some kudos on the original post ❣️. There will be more surprising little puzzles and articles like this in the future, so if you want to keep posted, follow my account on X!