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

I saw some code that uses the subs pragma to override perl's open function. I thought that would be a handy trick to know, so I tried a simple example:
use subs 'open'; sub open { print "opening file: @_\n"; CORE::open(@_); }
That didn't work for me, but when I changed the CORE::open line to the following, it did work:
CORE::open($_[0], $_[1]);
Any idea why that makes a difference?
Here's a little script that demonstrates the difference:

Given just an argument of "test.txt", it works. But if I run it with args of "test.txt bad", it fails. $! is empty even when it fails.

use subs 'open'; $file = $ARGV[0]; $method = $ARGV[1] eq 'bad' ? 0 : 1; sub open { my $count = scalar @_; print "opening file: @_ ($count)\n"; # Prints "opening file: TEST + [filename] (2)" for either method my $return; if ($method == 0) { $return = CORE::open(@_); # doesn't work } else { $return = CORE::open($_[0], $_[1]); # works } return $return; } if ($result = open (TEST, $file)) { my $lineCount; for my $line (<TEST>) { last if $lineCount++ > 5; print "$line\n"; } close TEST; } else { print "couldn't open test.pl\n"; print "error info: $!\n" if $!; print "more error info: $^E\n" if $^E; }

Replies are listed 'Best First'.
Re: use subs
by chromatic (Archbishop) on Jan 24, 2003 at 05:52 UTC

    "It didn't work" is pretty nebulous. Was there an error message?

    Lacking that, I suspect you may be running afoul of prototypes.

Re: use subs
by Gilimanjaro (Hermit) on Jan 24, 2003 at 15:14 UTC
    This almost certainly has to do with the subtle difference between an array and a list... Which is wonderfully explained by tilly in Arrays are not lists.
      I had a nice version that would check the number of parameters passed and call CORE::open with the correct number of parameters but after reading Arrays are not lists I realized that I could shorten it greatly by using @_[0..$#_]. Thanks tilly++ (where ever you are) for writing such a great node. Thanks Gilimanjaro++ for pointing it out.
      use subs 'open'; sub open { my $params = scalar @_; print "received $params parameters...\n"; my $filehandle = shift; print "received filehandle $filehandle...\n"; print "received list @_[0..$#_]...\n"; my $return; $return = CORE::open($filehandle,@_[0..$#_]); return $return; } my $result; $result = open(TEST); print $result,$/; close(TEST); $result = open(TEST, "test.txt"); print $result,$/; close(TEST); $result = open(TEST, "<test.txt"); print $result,$/; close(TEST); $result = open(TEST, "<", "test.txt"); print $result,$/; close(TEST);
      I have left all the print statements in there for debugging purposes.
        Did I miss something (upd.: yes, I did) or couldn't this be cut down to simply:
        use subs 'open'; sub open { print @_ . "parameters: @_\n"; CORE::open(@_[0..$#_]); }
        (I didn't test anything, so I may well be way off the mark.)

        Makeshifts last the longest.

        I figured that I would update this for the benefit of anyone who comes along and decides to try it. I went with Mr. Muskrat's idea and it has worked great. Recently I had a problem handling a first arg that is an undefined scalar, for example:
        open(my $file, "<", $file);
        Again tilly came to the rescue: see anonymous filehandle for overridden open sub.

        -Joe