The tadpole operators explained


Last time,¹ I introduced the tadpole operators. As you have probably figured out by now, it was a joke. There are no new tadpole operators.

But the sample code works. What's going on?

The tadpole operators are pseudo-operators, like the goes to operator or the sproing operator: They take advantage of existing language features, and come with a creative story.

The tadpole operators exploit two's complement arithmetic and overflow.² The __ENABLE_EXPERIMENTAL_TADPOLE_OPERATORS is just a red herring.

Start with the identity for two's complement negation

-x = ~x + 1

then move the -x to the right hand side and the ~x to the left hand side:

-~x = x + 1

If that was too fast for you, we can do it a different way: start with the identity for two's complement negation

-x = ~x + 1

subtract 1 from both sides

-x - 1 = ~x

and finally, negate both sides

x + 1 = -~x

To get the decrement tadpole operator, start with

-x = ~x + 1

and substitute x = -y:

-(-y) = ~-y + 1

subtract 1 from both sides and simplify -(-y) to y.

y - 1 = ~-y

Update: Justin Olbrantz (Quantam) and Ben Voigt provide a simpler derivation, starting with the identity for two's complement negation.

-x = ~x + 1
Rearrange terms ~x = -x - 1
Let x = ~y Let x = -y
-~y = ~(~y) + 1 ~-y = -(-y) - 1
-~y = y + 1 ~-y = y - 1

¹Why didn't I post it on April 1st? Well, for one thing, April 1st is overcrowded. Second, it would have interfered with the run-up to the //build conference. And third, yesterday was a holiday in the United States, and I tend to schedule lighter fare on holidays.

²This means that they don't work on a machine that does not use two's complement, or one which checks overflow. Still, maybe they'll be useful if you're entering the IOCCC or some other contest which values minimal code size or obfuscation (or both).

Comments (25)
  1. Boris says:

    I noted in the other thread that an April Fools' post would have to be technically false, but that one was false only in spirit.

  2. J Cobb says:

    And yesterday was a holiday in the UK too, so all good. :)

  3. Ben Voigt says:

    To get the increment version immediately with no sleight of hand, start with the identity Raymond uses (-x = ~x + 1) and substitute (~y) for x.  Then -~y = ~(~y) + 1.  But ~(~y) is just y so -~y = y + 1.  This is the same approach Raymond uses for the decrement tadpole, except that it uses the definition of bitwise inverse ~(~y) = y instead of additive inverse -(-y) = y.

  4. OldFart says:

    Mostly it demonstrated that people would rather post their own comments than read other people's comments.

  5. Stephan Leclercq says:

    Has anyone mentioned that the Tadpole operators could be written as ??– or -??-

  6. Wizou says:

    @Stephan Leclercq: with trigraphs enabled :) nice!

  7. Chris says:

    Wow, that is a rather nice use of trigraphs, the only other one I've seen being the WTF operator (??!??!). One more goofy thing to miss in C++17.

  8. Kevin says:

    >This means that they don't work on a machine that does not use two's complement, or one which checks overflow.

    Or any sufficiently intelligent optimizing compiler, since signed integer overflow is undefined behavior.  As we've seen, that can cause time travel among other things.

  9. Trevor says:

    Why does it not work when overflow is checked for? The only two times when overflow comes into play, it comes into play into +1 and -1 as well.

    For 8-bit signed, when x = 127, there is an overflow in both x + 1, and -~x = -(-128). When x = -128, there is an overflow in both x – 1, and ~-x.

    For all other cases, no overflow occurs in either.

    [I thought that ~-(-127) incurs overflow, but I guess not. -Raymond]
  10. mikeb says:

    These operations would be subject to overflow only in the same situations that a normal increment or decrement operation would overflow (unless I'm missing something). So that aspect isn't really a downside.  You're left with relying on two's-complement and the not-particularly-readable aspects being the downsides to this.

  11. Brian says:

    int a = 1<<31;

    int b = ~-0;

    int c = a/b;

    This causes an overflow error, even though b is not 0.  Clearly this is a bug in the tadpole operator.

  12. Louis says:

    @Brian: using b = (0-1) gives the same error. (Also, it's undefined behavior to shift a 1 into the sign bit.)

  13. John Doe says:

    I think the simpler issue is, what isn't undefined behavior in C and in C++?

  14. Harry Johnston says:

    This is why parenthesis should be mandatory.  (Yeah, I know – I'm such a spoilsport.)

  15. dirk gently says:

    Bad Raymond! Bad! Making jokes of the humourless computer geek community

  16. alex_sh says:

    @Engywuck: they should have used non-breakable space character instead.

  17. John Doe says:

    You should have left the explanation due one week after.  I was having quite a good time reading some of the comments: the naïve ones, the haters gonna hate ones, and the snarky ones.  Not so much for the explanatory ones.

  18. Stephan Leclercq says:

    It's so much simpler in Forth… No parentheses, no precedence rules. And like C, almost everything you can write has some undefined behavior, so you're not un uncharted territory :-) And, oh, btw, tadpole operators already exist in Forth, they're spelled 1+ and 1-

  19. Engywuck says:

    @Harry: it gets even "better": "strong spaces" to change precedence rules for the parser. Just add more whitespace in your formula and have that act as parentheses: nim-lang.org/…/manual.html

    I can understand some form of it, e.g. "3+4 * 5" *could* be different from "3 + 4*5", but this opens the box of pandora for no real reason. ( and ) should rule!

  20. madbrain says:

    Forth with problem the nothing quite you expect that order the in is that is…

  21. Justin Olbrantz (Quantam) says:

    Raymond,

    You credited the wrong person. I posted that simplified solution 2 1/2 hours before him blogs.msdn.com/…/10616865.aspx

    [Sorry. -Raymond]
  22. Justin Olbrantz (Quantam) says:

    To be fair, I wouldn't read all 115 comments in the old thread, either :P

  23. Joshua says:

    I think Raymond reads all comments to almost all threads. That's probably why certain endless debate topics get on his nerves (not naming any for the obvious reason).

  24. Neil says:

    Conveniently the sproing operator hardly (on the US or UK keyboards at least) makes use of the shift key, while the *(foo)-> is a relative nightmare.

  25. T. West says:

    We've seen this before…

    "No, this idea will never escape the confines of the blog post.  It was created specifically for humorous purposes, and we modified it so it could never survive in the wild."

    Then there's a report of someone being hit by a flying chess piece in a fairground.  "No, that was just a naturally occurring flying rook.  Totally unrelated."

    And then it starts.  A trickle, but it's too late.  The author obviously had no idea exactly how dangerous their idea was, and now it's infecting our communities at an astonishing rate.  Soon, we're being asked to wear helmets near roller coasters.

    I predict we'll see the first appearance of tadpole operators in the dailywtf.com within a year.  Within 2 year, it will have spread to our universities, and within 5, *I* will be dealing with it in code maintenance and review.

    Thanks a lot, Raymond.

    :-)

Comments are closed.

Skip to main content