http://www.perlmonks.org?node_id=412564


in reply to Use method/function signatures with Perl

I realize this is kind of a broad and lazy question, but I too have heard for years and years that source filters were the greatest source of evil. Now you are apparently advocating something different, that they are useful and non-evil.

I would love to think that they were non-evil, but the use.perl journal you refer to is sadly lacking, as it looks to me, actual facts. You just say "It worked fine for me and we only found one bug". Which sounds nice, but it sounds like a lot of other advocacy I've heard, some of which was true and some of which wasn't.

I don't want to sound overly negative or accusatory, but I was wondering if you could provide a little more in depth explanation as to why you previously considered filters evil and why they are no longer evil?
  • Comment on Re: Use method/function signatures with Perl

Replies are listed 'Best First'.
Re^2: Use method/function signatures with Perl
by Ovid (Cardinal) on Dec 06, 2004 at 02:42 UTC

    The answer is simple, really. Previously I disliked source filters because I knew they could be a source of serious bugs that could be difficult to find. Further, source filters can require all sorts of tweaking as we find this special case and that special case and struggle to ensure that we've covered them all.

    Now, however, Filter::Simple handles many of the "worst case" scenarios. For example, you no longer have as much concern about filtering quoted text, comments or POD. If I had to deal with that, this module would be much larger and probably would not have been written. As it stands, I merely filter the "code" portion of the target module and everything works.

    Another thing which has changed my mind is testing. I now do many things that I would never have dreamed about previously because I have the tests to immediately tell me if I've failed. I can reach for more powerful tools without worry about misusing them because of tests.

    And finally, dogmatism of any sort scares me. When someone says "never do X" I immediately want to find reasons why X might be a good thing to do. In this case, by allowign function signtures and multi-method dispatch, an entire class of bugs in Perl is almost completely eliminated. Further, this is a class of bugs that other languages generally don't have, so this puts Perl on more of an equal footing. For example, consider how the &name code would look in Java (given that we cannot exactly duplicate the behavior because it's not possible to have different return types for methods with the same name):

    public String name () { return name; } public String name(String name) { this.name = name; return name; }

    And doing that in Perl, as seen previously:

    sub name { my $self = shift; if (1 == @_ && ! ref $_[0]) { $self->{name} = shift; return $self; } elsif (! @_) { return $self->{name}; } else { croak "Unknown arguments to name()"; } }

    I thought Perl was supposed to be more concise? In cases like this, it's not. However, my code makes Perl about as concise as Java and still allows for the full power of Perl. Argument validation in Perl is so tedious that many people (including me) tend to ignore it. Sure, test suites frequently catch the resulting bugs -- but not always. Further, the edge cases get ignored. We find ourselves doing silly things like passing an array reference around until eventually someone tries to call a method on it and they have to trace through a call stack to find out where the arrayref was first passed.

    My code is an attempt to alleviate that problem and eliminate the ability to write these bugs. Safeguarding against problems is typically cheaper than fixing them. My personal experience with source filters has convinced me that, when used properly, the gains can tremendously outweigh the losses.

    Cheers,
    Ovid

    New address of my CGI Course.

Re^2: Use method/function signatures with Perl
by Ovid (Cardinal) on Dec 06, 2004 at 03:02 UTC

    You know, I just remembered something. I happened to mention that in my entire time using the source filter at my previous place of employment, only one bug bit me. I think it's worth looking at.

    The filter allowed method signatures, but it did not do multi-method dispatch, so it was far more limited in scope than mine. One thing it did do that mine does not is create prototype stubs for the functions. So this:

    sub foo($bar) { ... }

    Became this (more or less):

    sub foo($); sub foo { my ($bar) = @_; ... }

    Unfortunately, because it's difficult to distinguish a method from a normal subroutine, it created those prototypes for methods. With methods they are a almost a no-op. One day I had a method in a class that was probably not needed as there was a suitable method in a base class. In case I was wrong, I decided to comment out the method instead of deleting it. Can you spot the resulting bug?

    sub foo($$); # sub foo($self, $bar) {...}

    This fails horribly when I do $object->foo($stuff) because Perl sees that &foo is defined in the current symbol table and then tries to call it, but since there is no subroutine, it dies with an "Undefined subroutine" warning, even though I clearly had that method in a base class.

    That was a very difficult bug to track down and it caused a lot of confusion. One would think that this merely reinforces the "source filters are always bad" camp, but in reality, this bug stemmed from our not using Filter::Simple but instead relying on the older Filter::Util::Call. Had we used Filter::Simple, we would have filtered only on code and the one bug never would have bitten us. This module saved us so much time in development, though, that the time wasted tracking down this one bug was easily offset by the benefits gained by all developers using it.

    Cheers,
    Ovid

    New address of my CGI Course.