Image Courtesy of cottonbro. Modification by myself.
!+++!), and prototype pollution (both the dangerous and the ugly ways). 🧙♀️
If we pick
25.96 for our
number, the code above will return
Math.floor(number) is long, especially when you chain it with other functions. As someone who likes to use language features like the PHP spaceship operator to solve problems.
~~number even work? And how so? Should we use it? Let’s explore! 🧭
Now this is quite a creative way of using string conversion. And it’s even longer than
Math.floor(number). It has even more disadvantages, most notably, converting the number to a string. That is in and of itself an expensive operation.
Parsing it as an int
Now this is good, and shorter than
Math.floor. However, it is intended for strings and cannot be used in functional methods like
reduce. Moreover, as detailed in this stackoverflow answer,
parseInt also accepts “trailing characters that don't correspond with any digit”.
Type Coercion to the resuce!
NaN, “Not-a-Number”. But that also means that binary operators, such as binary AND (
a & b) and XOR (
a ^ b), can be used with types that are not a number, including the
There is a catch with using floating point numbers, so non-integers, for binary operations. It will either break your numbers or... coerce them to integers?
Yes, that’s exactly what the double-tilde “operator” does.
~~number for our example
25.95 will evaluate to
(number) internally, leading to the number being converted to a 32-bit signed integer. In fact, all the following operators will convert
number to an
Int32 in their calculations.
~number: binary NOT, returns
number << 0: left shift, returns
number >> 0: right shift, returns
And the following operators will convert
A @ B—with
@ being the operator and
B being numbers—likewise to 32-bit signed integers. See the specification.
number ^ 0: binary XOR, returns
number & number: binary AND, returns
number | 0: binary OR, returns
The Double Tilde
As we’ve just learned,
~number will convert our number to a 32-bit signed integer. Using
~~number will reverse the binary NOT operation and leave us with
25. Great! 🎉
You might want to point out concerns with maintainability. And you are absolutely right, let’s hold off on that though. There is a technical reason why you should never use the double-tilde to floor a number. It fails the overflow-test.
Let’s construct a reasonable example.
You have a business banking system which allows customers to create transactions. You know that using decimals is bad for currencies, so you use integers that count the amount of money in cent. Now, you want to floor the transaction amount to avoid other problems. That is why you use the double-tilde to round the incoming amount.
One day, a customer wants to transfer
4284967296 cent ($42,849,672.96) from their account to an account at another bank. You do your checks and then floor the amount with the double-tilde operator.
~~4284967296. Surprisingly, the balance of the customer’s account just increased by $10,000.
Wait... What? 🤔
The conversion to a 32-bit signed integer with
ToInt32(number) not only involves the
flooring but also a calculation of modulo 232 on the floored number. I'm not sure why this is done but my educated guess is that it is to avoid overflowing the 32-bit integer internally.
4284967296 % (2 ** 32) => -1000000
And now you have to explain your boss how using two tilde characters in your bank’s software calculation caused a customer to get $10,000 from you for free. If they had just read the documentation.
After learning that the answer to “Should we use it?” is a straightforward HELL NO, let’s just quickly consider the maintainability aspect of using an undocumented language feature.
Math.floor(number) expresses a clearer intent. And yes, probably if you have never used the operator before.
Using an undocumented hack that nobody understands—in the presence of a proper solution!—will make your code less understandable.
A few years ago, I got a double-tilde flooring through a code review but the reviewer asked me to comment what it does it because I argued it was more readable. Oh boy, was I wrong. As far as I know, this code is still out in the wild, although I might’ve changed it to a proper
Math.floor at some point... Luckily, I’ve never gotten the chance to implement this at a bank before finding out about it’s danger.
I leave you with this: don’t ever use the double-tilde “operator” for flooring a number. It’s bad at best and dangerous at worse. 🙅♀️