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.
5 Comments
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!
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.
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.
Of course, the CPAN version exists already. See Class::Autouse, particularly, the "superloader" option.
Excellent work, David.
Thank you for all the work you have been doing to make Perl even better.