Currently, I'm working on a Pomodoro timer application where I have an entity
called project-category. It has the following interface:
interface ProjectCategory {
name: string;
createdOn: number;
modifiedOn: number;
// ... some other fields
}
I've written a function that validates and instantiates a project category
object. In regards to the timestamp validation, I have implemented these rules:
If both the creation and modification timestamps are absent, assign them the
current timestamp.If both the creation and modification timestamps are present, then make sure:
that the modification timestamp is greater than or equal to the creation
timestamp.Otherwise, throw an error.
And the code looks something like this:
function makeProjectCategory( arg: Partial<ProjectCategory>): Readonly<ProjectCategory> {
const projectCategory: Partial<ProjectCategory> = {};
// ... timestamps validation
{
const isCreatedOnPresent = "createdOn" in arg;
const isModifiedOnPresent = "modifiedOn" in arg;
const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
// (isCreatedOnPresent && !isModifiedOnPresent) ||
// (!isCreatedOnPresent && isModifiedOnPresent);
if (isOneTimestampMissing)
throw new Error(
`Creation and Modification timestamps must be provided together.`
);
if (isCreatedOnPresent) {
// so both timestamps are present
assertValidTimestamps({
createdOn: arg.createdOn,
modifiedOn: arg.modifiedOn,
});
// ...
} else projectCategory.createdOn = projectCategory.modifiedOn = Date.now();
}
// ... other fields validation
return Object.freeze(projectCategory) as Readonly<ProjectCategory>;
}
After writing this code, I realized that the validation logic is similar to an
XOR logic gate.
isCreatedOnPresent | isModifiedOnPresent | isOneTimestampMissing (should throw ?) |
---|---|---|
true | true | false |
false | true | true |
true | false | true |
false | false | false |
So changed the following snippet
const isOneTimestampMissing =
(isCreatedOnPresent && !isModifiedOnPresent) ||
(!isCreatedOnPresent && isModifiedOnPresent);
to:
const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
Let me explain how it works.
Truth table of XOR logic gate
Input Bit A | Input Bit B | Resulting Bit |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
If the XOR operator (^
in JS) is applied on two bits, it returns:
-
1 (
true
) if they are alternating. -
0 (
false
) if they are the same.
So if you run the following snippet, you'll see:
console.log(1 ^ 1); // 0
console.log(1 ^ 0); // 1
console.log(0 ^ 1); // 1
console.log(0 ^ 0); // 0
But wait, in the above code snippet 1
and 0
doesn't represent a single bit!
Strictly speaking it's a 32 bit number. When the XOR operator is applied on two
numbers, first it converts the numbers to a binary form and then operates on
each bit at a time. Let me illustrate.
#1: 1 ^ 1 = 0
1: 00000000000000000000000000000001
1: 00000000000000000000000000000001
-----------------------------------
0: 00000000000000000000000000000000
#2: 12 ^ 15 = 3
12: 00000000000000000000000000001100
15: 00000000000000000000000000001111
------------------------------------
3: 00000000000000000000000000000011
Again, how does this (+isCreatedOnPresent ^ +isModifiedOnPresent
) code
work? The +
in front of two variables is called the Unary Plus Operator.
It coerces a value to number. So, +isCreatedOnPresent
is exactly similar to
Number(isCreatedOnPresent)
. And as these two variables are of type boolean
;
they are coerced to either 1
or 0
. Because in JavaScript:
Number(true); // 1
Number(false); // 0
Now, for example let's say, modifiedOn
is present in the arg
but
modifiedOn
is not. This is how the code will be evaluated:
// isCreatedOnPresent = true, and isModifiedOnPresent = false
const isOneTimestampMissing = +isCreatedOnPresent ^ +isModifiedOnPresent;
// = +true ^ +false;
// = 1 ^ 0;
// = 1;
if (isOneTimestampMissing)
// if (1)
throw Error()
// as 1 is a truthy value the error will be thrown
Conclusion
Honestly, I think it's not a good idea use the XOR (^
) operator in my code
just to reduce one line. Because for the sake of brevity it sacrifices
readability and can confuse someone who does not know about the XOR
operator. But, I found a real life use case of it and just wanted to share it
with you guys š.
Credits
The cover image (XOR Gate in Minecraft) is taken from Imgur .
Top comments (1)
thanks, was really interesting to read)