I originally posted this to my use.perl journal, but once again, I realized some monks might enjoy this.

Late at night, lots of coding and a little test program confused me for a moment until I looked at it again and almost laughed myself silly. I needed to test that I could read individual records in a file. The records are separated by a lone dot "." appearing by itself on a line. My intention was to open the file, read in individual records, remove that trailing dot and visually inspect the records one by one. Spot the bug:

#!/usr/bin/perl use strict; use warnings; my $file = shift || die "No file, dummy!"; open FH, "<", $file or die "Could not open ($file) for reading: $! +"; local $/ = "\n.\n"; while (defined (my $record = <FH>)) { chomp $record; print $record; <STDIN>; }

If you post the answer, do so as a spoiler, please.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Spot the Bug
by tilly (Archbishop) on Sep 09, 2005 at 04:06 UTC
    Lemme guess...
    You expected it to give you the next record when you hit return. But <STDIN> was expecting "\n.\n". So you got one record, hit return, and wondered why you didn't get anything more. :-)

    There are other bugs that I can see potentially being an issue as well. But this is the most obvious one.
Re: Spot the Bug
by ambrus (Abbot) on Sep 09, 2005 at 10:55 UTC

    Nice bug. It took some time for me to realize it.

    First I thought that chomp can't remove the multi-character suffix. But it can. The real bug is

Re: Spot the Bug
by pg (Canon) on Sep 09, 2005 at 01:57 UTC
    use strict; use warnings; # my $file = shift || die "No file, dummy!"; # open FH, "<", $file or die "Could not open ($file) for reading: $ +!"; local $/ = "\n.\n"; while (defined (my $record = <DATA>)) { chomp $record; print $record; # <STDIN>; } __DATA__ sdjh sfhg srig srgsrigh . . . asdigf wsergh

    This gives:

    sdjh sfhg srig srgsrigh.asdigf wsergh

    A . was left there unremoved, if that's the bug you are looking for (As it cannot handle empty record.)

      For enlightenment, uncomment the code that you commented out one line at a time until the bug rears its ugly head.

        The other thing is that <STDIN>. It does not return in the normal way, which is expected base on the code, as line break has been reset to "\n.\n". But you can easily get around by entering "\n.\n" (<Enter>.<Enter>) to continue and inspect the next record.

        Any way, my first reply still reveals a bug, if the program is required to handle empty record.

      That would be a bug if my data were structured that way, but they were in a guaranteed format. Nice idea, though.

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Spot the Bug
by Anonymous Monk on Sep 09, 2005 at 04:32 UTC

    To be frank, it is quite unfair to ask people to guess that one bug you stumbled on, when there are quite a few other bugs exist, as other monks have already pointed out.

    I believe that you were stuck for a while with that <STDIN> as pg and tilly has pointed out, but that was just the one bug that was obvious...

      Wasn't particularly trying to be difficult. I should have mentioned that I had a guaranteed file format. The <STDIN> issue is the only in that code which I can think of which pretty much has to be a bug (in that it violates expectations, even though it's doing what I asked). Of course, some would argue that perhaps one would intend that they be able to type a "." to continue and thus it's not a bug, but that would be getting pedantic, I think.

      Cheers,
      Ovid

      New address of my CGI Course.

        Well, I was able to *find* the <INPUT> bug, but i was not able to *spot* it. So, what I will meditate on briefly is *finding* (slow) versus *spotting* (fast).
        What I did: run the code with some test data, run it, look up $/ in perlvar, realize that's not the problem, read the code again, and finally realize the problem. Total time, maybe five minutes.

        So, in this case, the perlish var threw me off. If the code had been written

        #!/usr/bin/perl use strict; use warnings; use English; my $file = shift || die "No file, dummy!"; open FH, "<", $file or die "Could not open ($file) for reading: $!"; local $INPUT_RECORD_SEPARATOR = "\n.\n"; while (defined (my $record = <FH>)) { chomp $record; print $record; <STDIN>; }
        I probably would have spotted it a lot faster. So maybe the "best practices" moral here would be to use English when doing this kind of magic thing. Even if you're a perlvar wiz, the guy maintaining your code may not be.

        The second moral of the story is, with regards to finding versus spotting: if you've got a short little chunk of code like this and you know it's got a bug in it, read through every line. Read the first line. Think about it. Read the next line. Think about it. Until you've read every line. Seems like an obvious thing to do, but I am not in the habit of doing it. I am in the habit of write, try it out, check for bugs. I don't usually write then check for bugs.

        But of the two morals, I think use English would probably save more time in the grand scheme of things. I may put this on my list of best practices now for everything other than $_. (I wonder whether damian conway mentioned the subject in his book?)