morgon has asked for the wisdom of the Perl Monks concerning the following question:

Venerable Monks,

I am currently looking for "near miss" examples in Perl.

More specifically I am looking for innocently looking code-examples that are almost but not quite correct and fail spectaculary.

Maybe an example clarifies what I am looking for:

Imagine this piece code:

use strict; my @a=(1..100); for my $i (0..@a-1) { print $a[i]; }
This may be not an idiomatic way to loop but it is semantically ok: @a-1 (in scalar context) is the index of the last element in @a;

Now imagine someone refactors this to use an array-ref instead of an array like this:

use strict; my $a=[1..100]; for my $i (0..$a-1) { print $a->[i]; }
This looks similar to the above but is now only "almost" correct - the problem is the expression $a-1. Unfortunately a array-ref in numeric context returns the memory-location (usually a LARGE number) and so this code will probably loop for a very long time (and/or run out of memory eventually). And in case you ask: No, I am not making this up, I have seen it happen...

Anyone with similar examples?

Many thanks!

Replies are listed 'Best First'.
Re: catastrophic near misses in Perl
by repellent (Priest) on Apr 18, 2009 at 02:19 UTC
    Not quite related, but you may want to read Inconsistent for the sake of convenience.

      More specifically I am looking for innocently looking code-examples that are almost but not quite correct and fail spectaculary.

    Huh? So you are looking for.... subtle bloopers? Where are you going with this?
Re: catastrophic near misses in Perl
by CountZero (Bishop) on Apr 18, 2009 at 07:08 UTC
    Well, the archetypical "near miss" error is the off-by-one. This will hit you mostly when doing C-style for loops.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: catastrophic near misses in Perl
by moritz (Cardinal) on Apr 18, 2009 at 09:02 UTC
    Search for "don't use", you'll find lots of things that people recommend not to use, sometimes with good reason.
      I think better is to emphasize what TO DO rather what not.

      At the very top of my list is:
      1. Always "use strict;" - this is a compile time directive and has no run time penalty.
      2. Almost always run with run time warnings enabled. Turning this off for well debugged apps that are extremely performance critical and written by experienced Perl programmers can be considered. However this should never be your first thought about "how to I speed this up?".

Re: catastrophic near misses in Perl
by ruzam (Curate) on Apr 18, 2009 at 16:08 UTC
    Take
    sub my_function { my $self = shift; my $parm = shift; return $self->{parm}; }
    Now refactor it as
    sub my_function { shift->{shift} }

    It looks like it should be the same, but the second shift has now become a literal 'shift' and not a shift function. I wouldn't say it fails spectacularly (well I suppose it could depending on the expected results), but it's darn hard to catch by just looking.

Re: catastrophic near misses in Perl
by dsheroh (Monsignor) on Apr 18, 2009 at 11:22 UTC
    On another forum, someone recently posted a problem involving the code:
    my $var while (some_condition) { ... }
    It refused to run, complaining of a syntax error near ") {".

    Everyone focused on the ")" and "{", some speculating that perhaps the issue was the linebreak between them.

    The actual problem was, of course, the lack of semicolon after my $var. (my $var while (some_condition); is valid (if pointless) Perl, causing the error when perl saw a while positioned to control statements both before and after it.)

    So is that the general type of example you were looking for?

      No, thats a syntax error, he wants brainfarts
Re: catastrophic near misses in Perl
by Marshall (Canon) on Apr 18, 2009 at 09:31 UTC
    I am also flummoxed as to what you want. In your example, you started with what looked like "non-idiomatic" code at first glance that became even worse code. There are lots of ways to write bad code. I don't see how a thousand examples of that would be helpful.

    Also I would say that the very most important thing that was wrong with this code is lack of "use warnings;", either by explicit "use warnings;" statement or on sheebang line: #!/usr/bin/perl -w. Many Windows users don't understand that the Windows ports of Perl will use the -w option on this line EVEN THOUGH the /usr/bin/perl part is meaningless!

    Had you enabled warnings, your code shows a run time error with the print statement, "use of uninitialized value". This would be true even if not printing, but rather just looping and trying to do something with the values in @a. Now Perl tries to keep running and you will get untold numbers of this print line. But this is actually a feature, not a defect in Perl. Run time warnings do slow the code down a small bit, but this penalty is almost always worth it!

    A super common error in programming is "off-by-one". Proper Perl coding greatly reduces this chance!

    Simple re-coding to not use $i as an index...
    It is actually very seldom that our FORTRAN buddies: i,j,k,l,m,n are needed in Perl! (for the young folks, i-n are first 2 letters of integer and the use of these as short term looping integers pre-dates C).

    #!/usr/bin/perl -w use strict; my @a=(1..100); for my $num (@a) #foreach my $num (@a) is also just fine { print "$num\n"; } my $b=[1..100]; foreach my $num (@$b) { print "$num\n"; }
    There is a difference between "for" and "foreach", but it really doesn't matter in this example.
      There is a difference between "for" and "foreach", but it really doesn't matter in this example

      Care to elaborate? perlsyn#foreach says

      The "foreach" keyword is actually a synonym for the "for" keyword, so you can use "foreach" for readability or "for" for brevity.