Patching the Perl core for lazy file handle objects

Last night I was inspired to patch the Perl core to load IO::File on demand when calling a method on a file handle would otherwise die. This effectively makes file handles actual "lazy" IO::File objects. If you want to use file handles procedurally, you never need IO::File. But if you try to treat handles as objects and call methods on them, IO::File gets loaded when you need it.

Here's how it works. As of Perl 5.12, internally, Perl 5 file handles are represented as IO::File objects:

$ perl -E 'say(ref(*STDERR{IO}))'
IO::File
$ perl -E 'open my $fh, ">", "/dev/null"; say(ref(*{$fh}{IO}))'
IO::File
$ perl -E 'my $str; open my $fh, ">", \$str ; say(ref(*{$fh}{IO}))'
IO::File

However, trying to call methods on them fails if you haven't loaded IO::File (or a parent class like IO::Handle):

$ perl -E 'STDOUT->binmode(":utf8"); say "\x{263a}"'
Can't locate object method "binmode" via package "IO::File" at -e line 1.

With the patch I wrote, just before such a method call would die, if the call is on an IO::File object and $INC{'IO/File.pm'} doesn't exist, Perl attempts to load IO::File and tries to resolve the method again:

$ bleadperl -E 'STDOUT->binmode(":utf8"); say "\x{263a}"'
☺

This has zero performance impact on code that doesn't call methods on file handles or that loads IO::File (or a parent class) before calling a method on a file handle. It only kicks in when Perl would otherwise die on you.

Barring any issues emerging, this feature will be available in the development release of Perl 5.13.8 on or around December 20, just in time for Christmas.

This entry was posted in p5p, perl programming and tagged , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

5 Comments

  1. Posted November 30, 2010 at 6:55 am | Permalink

    Yesssssss!

    I actually ran into this a couple of days ago and was slightly annoyed it didn't just work. That the next version of Perl will probably solve this is simply incredible, makes me happy to be a Perl programmer :)

    Thanks Dave!

  2. brian d foy
    Posted November 30, 2010 at 7:36 am | Permalink

    I've wanted this sort of feature for general objects, but especially for IO::Handle objects since some of that is inside the perl source.

    Is there any reuse for general module loading, maybe even if people can only turn it on with a pragma? I've wanted something like autouse without the declaration of the use of modules.

    • Posted November 30, 2010 at 7:45 am | Permalink

      It would be pretty trivial to do, but I didn't think a general change like that would have been welcome so I limited it to IO::File. The nice thing about this change is that it's down in a "about to die" segment of code, so there's no overhead. I suspect that a CPAN module might be able to hook method resolution and handle it, but that might have overhead. If you can get p5p enthusiastic about the idea, I'm willing to do the extra work of exploring having a pragma to turn it on generally.

      • Posted November 30, 2010 at 7:48 am | Permalink

        Of course, the CPAN version exists already. See Class::Autouse, particularly, the "superloader" option.

  3. prakash
    Posted December 1, 2010 at 4:16 pm | Permalink

    Excellent work, David.

    Thank you for all the work you have been doing to make Perl even better.

© 2009-2014 David Golden All Rights Reserved