Note to my future self...

Note to my future self...

Be careful inverting an if statement that's comparing integers.

if SomeInt = SomeOtherInt then
  //...
else
  //...

The following:

if not SomeInt = SomeOtherInt then

Does a bitwise negation of SomeInt before comparing it to SomeOtherInt. The correct inversion is:

if not (SomeInt = SomeOtherInt) then

or

if SomeInt <> SomeOtherInt then

Comments

  1. A pair of parentheses too many, is better than a pair too few.

    ReplyDelete
  2. That's not the strict typing I'd expect from Delphi, which was after all born as Turbo Pascal. Since when is negation a meaningful operation on an integer?!? Stupid C idiom! Bet you that is not in the Wirth standard.

    ReplyDelete
  3. Common bit flag operation, IMO.
    Turn off bit x: flags := (not x) and flags;

    ReplyDelete
  4. Yes, exactly, Lars Fosdal. And it's very C to see an integer as a bucket of bits. Sure, it's implemented that way on all computer architectures I know of -- but conceptually a totally different animal(1). Getting that mixed up is essentially the opposite of strong typing; it's what assembler and C are all about, but what the Pascal family of languages is all about avoiding. If this bug can happen in Delphi, that's only because Delphi has betrayed its Pascal roots.

    ----
    (1): You can't do logical operations on integers -- like, what's "the opposite of 137" supposed to mean?!? (The closest you could get would be -137, I suppose, but that's not what you get from a bit-flip, is it? Not guaranteed, not on all architectures... Because it's a totally different category of operations.)

    ReplyDelete
  5. Anyone that has interfaced hardware in any language will see it as completely natural.
    It has always been a documented feature of TP, BP, BPW and Delphi, and hence not pant-twisting material.

    ReplyDelete
  6. But - should there be a warning if the compiler does bitwise operations on integers in a statement that is assigned to a boolean, and the result is not cast as boolean? 
    I'd support that.

    ReplyDelete
  7. Lars Fosdal Moreover, it is simply consistent now with operator precedence rules. Set aside the issue of bitwise inversion--although as a hardware guy, I would point out that it's important to have, and makes perfect sense--and what you have left is then (possibly) an exception to operator precedence. In the end, it is simply more readable, in any event, with the parentheses.

    ReplyDelete
  8. Oh sure, of course I agree it's useful, even important, to be able to invert bits in a byte or word or whatever; I'm just saying the container shouldn't necessarily be called an integer. I mean, once you use some variable for that purpose, you're not likely to do many ordinary integer-arithmetic operations on it, are you: "BagOfPrinterStatusBits := BagOfPrinterStatusBits * 4;"...?

    What I meant was only that it would have been safer, and more in keeping with the original spirit of the language, to use one type (and types like byte and word and so on have been around for a good while, haven't they?) for bit-storage and another for integer arithmetic, with only bitwise operations defined for the one, and only integer arithmetic for the other. Then, if you sometimes absolutely need to do both in one variable, then make it of the type whose operations you'll do most of, and cast it to the other for the rest. That way the parser won't get confused by "not IntVar = OtherInt", because with the bit-flip not being defined for IntVar, it can only mean the whole expression.

    (Checks in trousers... No, my underwear doesn't seem to be all that much twisted from that. Why, should it be? Is yours?)

    ReplyDelete
  9. For Pascal, the original bit oriented type is a set.  But - sets are impractical for boolean operations. There is a reason that Pascal adopted the C like integer based boolean arithmetics: They are practical.

    ReplyDelete
  10. 'Xackly. Not sure how well that casts to an integer/byte/word/whatever, though, which might be necessary if you a) are going to sometimes treat it as am integer, or b) interface it woth external low-level routines, like the hardware guys... "Implementation-dependent", izzit? See, even I have some understanding for the C idiom! :-D

    ReplyDelete

Post a Comment