Ruby unary tilde (`~`) method

For fixnum, it's the one's complement, which in binary, flips all the ones and zeros to the opposite value. Here's the doc: http://www.ruby-doc.org/core-2.0/Fixnum.html#method-i-7E. To understand why it gives the values it does in your examples, you need to understand how negative numbers are represented in binary. Why ruby provides this, I don't know. Two's complement is generally the one used in modern computers. It has the advantage that the same rules for basic mathematical operations work for both positive and negative numbers.


The ~ is the binary one's complement operator in Ruby. One's complement is just flipping the bits of a number, to the effect that the number is now arithmetically negative.

For example, 2 in 32-bit (the size of a Fixnum) binary is 0000 0000 0000 0010, thus ~2 would be equal to 1111 1111 1111 1101 in one's complement.

However, as you have noticed and this article discusses in further detail, Ruby's version of one's complement seems to be implemented differently, in that it not only makes the integer negative but also subtracts 1 from it. I have no idea why this is, but it does seem to be the case.


Using pry to inspect the method:

show-method 1.~

From: numeric.c (C Method):
Owner: Fixnum
Visibility: public
Number of lines: 5

static VALUE
fix_rev(VALUE num)
{
    return ~num | FIXNUM_FLAG;
}

While this is impenetrable to me, it prompted me to look for a C unary ~ operator. One exists: it's the bitwise NOT operator, which flips the bits of a binary integer (~1010 => 0101). For some reason this translates to one less than the negation of a decimal integer in Ruby.

More importantly, since ruby is an object oriented language, the proper way to encode the behavior of ~0b1010 is to define a method (let's call it ~) that performs bitwise negation on a binary integer object. To realize this, the ruby parser (this is all conjecture here) has to interpret ~obj for any object as obj.~, so you get a unary operator for all objects.

This is just a hunch, anyone with a more authoritative or elucidating answer, please enlighten me!

--EDIT--

As @7stud points out, the Regexp class makes use of it as well, essentially matching the regex against $_, the last string received by gets in the current scope.

As @Daiku points out, the bitwise negation of Fixnums is also documented.

I think my parser explanation solves the bigger question of why ruby allows ~ as global unary operator that calls Object#~.