Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

using Exporter to overwrite a core function

by Forsaken (Friar)
on Apr 09, 2005 at 18:41 UTC ( [id://446279]=perlquestion: print w/replies, xml ) Need Help??

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

Enlightened monks, in my eternal search for ways of making things more complicated than they need to be, I am currently working on a module that artificially buffers data from one or more filehandles, allowing one to read data 1 line at a time, while still using unbuffered reading.

However, in order to avoid all sorts of nastiness, I am attempting to overwrite the sysread() call with a replacement of my own, and using Exporter to replace the original sysread() by placing my own function into @EXPORT_OK. However, when using the module and importing sysread, it seems that what in fact happens is that *both* the imported function and the original system function are being called on, in that order.

Now, I am fully aware that what I am doing here is somewhat, if not horribly, Wrong(tm) so please don't lecture me :-) Could someone enlighten me as to if, and if so how, it is possible to achieve what I am trying to do here?

My greatest thanks go out to you all in advance.

  • Comment on using Exporter to overwrite a core function

Replies are listed 'Best First'.
Re: using Exporter to overwrite a core function
by jpeg (Chaplain) on Apr 09, 2005 at 19:33 UTC
    One of the purposes of & (in 5.8.x) is to force the interpreter to use your own function. However, I've only seen examples of it overriding builtins with subs defined in the same script, not imported. Maybe
    use Foo; ... my $wuzzie = &Foo::sysread(FH, $scalar, $length);
    would do it?
    Or perhaps just &sysread(FH, $scalar, $length).
    --
    jpg
Re: using Exporter to overwrite a core function
by tlm (Prior) on Apr 09, 2005 at 20:47 UTC

    It would be nice to see some of your code, but basically you need to use the subs pragma. Here's an example:

    use strict; use warnings; package Happiness; use subs 'die'; sub die { local $| = 1; print "Don't worry, be happy\n" } die "Good-bye, cruel world!\n"; warn "Suicide attempt failed\n"; CORE::die "OK, THIS time I'm outta here!\n"; __END__ Don't worry, be happy Suicide attempt failed OK, THIS time I'm outta here!
    There's a nice discussion of this in perlsub.

    the lowliest monk

      well, here's basically the idea:
      Package Foo; use strict; use Exporter; use vars qw(@EXPORT_OK); @EXPORT_OK = (&sysread); sub sysread { print "this is not the real thing\n"; } Package Bar; use Foo qw(sysread); print "about to test sysread\n"; sysread;
      Basically this generates *both* the "this is not the real thing" message from the imported sub as well as the "not enough arguments for sysread" error message from the core call.

      What really dazzles me is not even the fact that it doesn't quite work the way I want it to, but that in fact both functions are being called on.

        I know you requested no lectures, but the code you posted had some fundamental errors that make me wonder whether it is a good idea for you to be playing with fire. It's your business if you want to hang yourself, but I feel uneasy handing you the rope for it. I just had to get this off my chest. OK, end of sermonette.

        I found at least three major errors in your code (more if all the code was intended to reside in a single file). The first one is that it's package, all lower case. What you wrote is equivalent to Foo->Package (see perlobj) . Next, it is not enough to use Exporter; you need to make your class a subclass of it. Like this:

        package Foo; use Exporter; our @ISA = ( 'Exporter' );
        or (my preferred idiom):
        package Foo; use base 'Exporter';
        (There are more idioms for doing this; see perlobj). The third thing is that the entries in @EXPORT, @EXPORT_OK, etc. are supposed to be strings. Something like @EXPORT_OK = ( &frobozz ) will put the value returned by the frobozz subroutine (whatever that is) in @EXPORT_OK, which, unless frobozz is the rare function that narcissistically returns its own name, won't do you any good.

        OK, so here's what you do:

        # file Foo.pm package Foo; use strict; use warnings; use Exporter; our @ISA = ( 'Exporter' ); our @EXPORT_OK = ( 'sysread' ); sub sysread { warn "this is not the real thing\n"; } 1; __END__ # file test.pl use strict; use warnings; package Bar; use Foo 'sysread'; warn "about to test sysread\n"; sysread; __END__ % perl test.pl about to test sysread this is not the real thing
        Note that the code in the example above is split over two files; it won't work as written if you put it all in one file.

        Definitely give a very good read or two to the relevant section of perlsub that I cited before.

        the lowliest monk

Re: using Exporter to overwrite a core function
by Zaxo (Archbishop) on Apr 10, 2005 at 08:20 UTC

    Or you could do it the old-fashoned way:

    BEGIN { *CORE::GLOBAL::sysread = sub (*\$$;$) { # whatever }; }
    The prototype is probably desirable in this case; it comes from perl -e'print prototype "CORE::sysread"'.

    If you want to limit the damage, you can localize the effect to a dynamic scope:

    { local *CORE::GLOBAL::sysread = \&mysysread; # do things that call builtin sysread } # no more replacement from here on

    After Compline,
    Zaxo

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://446279]
Approved by Joost
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (7)
As of 2024-04-23 13:30 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found