in reply to Re: Re: Re^3: Can you spot the problem?
in thread Can you spot the problem?

However "something that doesn't even make sense" is a somewhat stronger statement than "bad design"

In some respects, I agree with the statement that the original code as posted doesn't make sense. It "feels" to me like something that would be posted as Obfuscated Code, because instead of going about solving the problem in any normal way, it attempts to abuse certain lowlevel features of the dataset in order to achieve a counterintuitive solution.

Normally, one would not expect to be able to compare four numbers with a fifth number by bitwise or-ing the four numbers together and comparing the result to the fifth number. In the general case, this would not work. It took me three readings of the code to understand why the author *expected* it to work. Of course, it doesn't, because he ignored something else that is comparably low-level in nature to the thing he was exploiting.

The code is attempting (and failing) to take advantage of some lowlevel details not only of how the language works but also lowlevel details of the dataset and of the problem. If 256 weren't a power of two, there wouldn't even be a presumption that it might work. It's a lowlevel bit-fiddling dirty-trick (attempted) solution to a higher-level problem, by no means a natural way to go about the thing at hand. Notice I did not say it isn't *the* natural way; I said it is not *a* natural way at all. Id est, it doesn't make sense.

People who write code like this *deserve* to get bitten by lowlevel details. (Of course, if you're just fooling around and the results don't matter, then getting bitten isn't such a big deal.)


;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print

Replies are listed 'Best First'.
Re: Re: Can you spot the problem?
by Roy Johnson (Monsignor) on Mar 05, 2004 at 22:13 UTC
    Would you feel better about (($a|$b|$c|$d) >> 8) == 0? The intent is to check that each component is one byte, and bitwise or-ing them is consistent with the bit-fiddling nature of what's being tested.
    If 256 weren't a power of two, there wouldn't even be a presumption that it might work.
    It's clear that you didn't see this as a bit-fiddling scenario, but it is. What, after all, is an IP? It's a four-byte string, translated into human-readable form.

    The PerlMonk tr/// Advocate
Re^2: Can you spot the problem?
by adrianh (Chancellor) on Mar 05, 2004 at 22:31 UTC
    Normally, one would not expect to be able to compare four numbers with a fifth number by bitwise or-ing the four numbers together and comparing the result to the fifth number. In the general case, this would not work. It took me three readings of the code to understand why the author *expected* it to work.
    If 256 weren't a power of two, there wouldn't even be a presumption that it might work. It's a lowlevel bit-fiddling dirty-trick (attempted) solution to a higher-level problem, by no means a natural way to go about the thing at hand. Notice I did not say it isn't *the* natural way; I said it is not *a* natural way at all. Id est, it doesn't make sense.

    This is why it's arguable :-) Things like this depend so much on experience with the domain and various programming styles. For me the authors intent was immediately obvious and the style a completely natural one. I can imagine writing the same code myself. I fiddle with IP addresses a great deal in various languages, and you're doing bit-mask type operations on them all of the time. I think about IP addresses and net masks in terms of bits and bytes. So, to me, boolean logic makes complete sense in this particular domain.

    The problem for me is that you get bitten by Perl's DWIMary. In Perl you're trained think that Perl will do the "right thing" when given things that look like numbers. In this particular instance Perl doesn't. I think it's a good thing that the Perl 6 folk are giving us separate operators to prevent future confusion.

    I can completely see your point of view, and it's nothing I'd start a religious war over, but I do think it's arguable.

      So, to me, boolean logic makes complete sense in this particular domain.

      Boolean logic is a natural way to solve the problem. A recursive or iterative solution would also be natural. The OP however instead attempted to combine the individual bits of the four parts of the address (only, they didn't combine quite the way he expected). I'd wager that the person who wrote this code has spent significant time working with a relatively low-level third-generation language such as C. (Especially, since it came off a non-Perl mailing list originally, but you can tell also from the style of the code.)

      The problem for me is that you get bitten by Perl's DWIMary. In Perl you're trained think that Perl will do the "right thing" when given things that look like numbers.

      Yeah, but in Perl you're not trained to write code like that. The code in question looks distinctly like it was written by a C programmer. (C programmers play weird tricks with bitwise operations all the time.) There are much more Perlish ways to solve the problem, not least of which is to use Regex::Common. I stand by my statement that in some respects I agree with the poster who said the code doesn't make sense; particularly, it may not make immediate sense to a Perl programmer with little background in C (and languages like C).

      I can completely see your point of view, and it's nothing I'd start a religious war over, but I do think it's arguable.

      It does depend on your perspective. I suppose the guy who wrote the code thought it made sense. (Of course, he also thought it would work...) But I don't think it's surprising that to flyingmoose, a Perl programmer, it didn't make sense. And, in a way, he's right. After three readings I understood why the author thought the code would work, but on the other hand, fundamentally he's using a bitwise operation to accomplish a logical operation. That is, he's doing bitwise-or of four numbers together in order to figure out whether all of them (logical and) meet a certain condition. Assuming for the moment that we apply tye's two-stroke fix that makes the code work as intended, it still only works because of certain bit-related properties of the numbers in question (centering around the fact that 256 is a power of 2). You can see why someone might view this as unintuitive.

      As far as an IP address being under the hood a single four-byte number, if the code used pack/unpack or something to convert the four numbers into a single four-byte number, or a hex representation, and then operated on that, I would consider that a (not the, but a) natural solution. In fact, for certain more complex IP-address calculations, especially having to do with network masks, that might even be _the_ natural solution. But the code in question doesn't treat the IP address as a four-byte number; it doesn't really do anything even _similar_ to treating it as a four-byte number. If anything, it tries to treat it as N sets of four bits, and checks to see whether N is more than 8. That's a completely different approach from treating it as a single 32-bit number.

      So, in conclusion, flyingmoose is not smoking crack (or, at least, if he is, you can't tell that from the node in question).


      ;$;=sub{$/};@;=map{my($a,$b)=($_,$;);$;=sub{$a.$b->()}} split//,".rekcah lreP rehtona tsuJ";$\=$;[-1]->();print
        Assuming for the moment that we apply tye's two-stroke fix that makes the code work as intended, it still only works because of certain bit-related properties of the numbers in question (centering around the fact that 256 is a power of 2).

        In this particular domain each number should be a single byte. The bit related property isn't arbitrary or coincidental - it's the very essence of the thing we're testing for. To me it's an obvious property that or-ing them together should result in a number less than 256. To others it may not be.

        You can see why someone might view this as unintuitive.

        Of course. It's a completely reasonably attitude. Just not a universal one.

        To others, myself included, using a bitwise numerical or is a completely intuitive solution. Whether somebody find it obvious or not is going to be dependent on their experience.

        I too would use Regexp::Common, but only because I loathe reinventing wheels. Are the regexpes that Regexp::Common::net uses internally any more or less "intuitive" that the other solutions offered? This, of course, depends on how familiar you are with Perl's regular expressions. It also depends on the domain you're playing with.

        I still think the real problem is with the behaviour of the | operator in Perl. This is one of the very few places where the difference between a string containing a number and a number makes a real difference.

        With all the other numerical operations numbers and strings containing numbers are treated the same way. It's only the bitwise operators that are treated differently. This, in my opinion, was a poor design choice and doesn't fit in with the way the rest of Perl is organised (eq vs ==, . vs +, etc.) I imagine this is one of the reasons the numerical and string bitwise operators are being separated out in Perl 6.

        For example, the difference between the bitwise string and numerical operators has caught me out when I was manipulating preference values that were being represented as bit masks. Comparing different preferences sometimes worked and sometimes didn't, depending on whether preferences got injected into the system as strings or numbers. Since the injection of values happened a long way from the comparisons it took a heck of a long time to figure out what was going on.

        (For those about to chime in and say bitmasks were a poor choice for preference values - I quite agree. We were manipulating values from a third party application.)

        So, in conclusion, flyingmoose is not smoking crack (or, at least, if he is, you can't tell that from the node in question).

        I never accused anybody of smoking crack.

        Ignoring the reinventing the wheel issue, and just comparing the bitwise and comparison solutions, on some days I might even agree that the comparison solution was a better design choice.

        However I do disagree that the original solution "does something that doesn't even make sense". It makes perfect sense - it's just that Perl in this particular instance does something that most developers wouldn't expect.