Hi! Please consider following me on twitter: @hanekomu.

PerlIO::via and autovivifying namespaces

PerlIO::via, in perl 5.10.0 at least, has a bug, or let's call it an unintuitive feature. To start, let's look at this excerpt from its manpage to see what it should do.

The PerlIO::via module allows you to develop PerlIO layers in Perl,
without having to go into the nitty gritty of programming C with XS as
the interface to Perl.

One example module, PerlIO::via::QuotedPrint, is included with Perl
5.8.0, and more example modules are available from CPAN, such as
PerlIO::via::StripHTML and PerlIO::via::Base64.  The
PerlIO::via::StripHTML module for instance, allows you to say:

       use PerlIO::via::StripHTML;
       open( my $fh, "<:via(StripHTML)", "index.html" );
       my @line = <$fh>;

to obtain the text of an HTML-file in an array with all the HTML-tags
automagically removed.

Please note that if the layer is created in the PerlIO::via::
namespace, it does not have to be fully qualified.  The PerlIO::via
module will prefix the PerlIO::via:: namespace if the specified
modulename does not exist as a fully qualified module name.

As the manpage later explains, the way to create these I/O layers is to declare certain subroutines like PUSHED(), OPEN(), WRITE() or CLOSE() in the layer package.

So I've written a simple layer that uppercases everything that passes through. Imaginatively, I'm calling this layer Foo, and, for demonstration purposes, I'm only writing the bare minimum to make it work.

#!/usr/bin/env perl
use strict;
use warnings;

package PerlIO::via::Foo;

sub PUSHED { bless {}, shift }
sub OPEN   { 1 }
sub WRITE  { print uc $_[1]; length $_[1] }
sub CLOSE  { 0 }

package main;

open my $fh, '>:via(Foo)', 'whatever' or die $!;
print $fh "Hello\n";
close $fh;

This program runs as expected and prints:

HELLO

To demonstrate the bug, let's add a simple package declaration.

package Foo::Bar;

We didn't declare any subroutines or variables in that package, just the package itself. When we run the program now, it prints:

Function not implemented at ./test.pl line 15.

What's going on?

When we declare the Foo::Bar package, the Foo namespace seems be autovivified, that is, it seems to magically spring into existence. PerlIO::via only seems to check whether the unqualified namespace — Foo in this case — exists and if so, whether there is a PUSHED() subroutine in it. If there isn't, it declares ENOSYS, that is, Function not implemented. It does not try to fallback on the fully qualified namespace — PerlIO::via::Foo in this case — like AUTOLOAD would.

I think it should fallback, so I consider it a bug in PerlIO::via, or at least a very unintuitive feature.

Tags: .

Write a comment | Bookmark and Share

posted at: 13:12 | path: /dev | permalink | 0 comments | 0 trackbacks