“Cuckoo” CPAN packages

“Cuckoo” packages are those that exist in a file that isn’t named after that package. Neil Bowers coined the term after the cuckoo birds, which lay their eggs in the nests of other birds (see, for instance, “Nest stealing cuckoo birds are locked in evolutionary war with their would-be victims”). He noticed that these “cuckoo” packages aren’t in Module::CoreList, the module which tracks which versions of modules came with which perls.

The Cowbird's Nest

For example, in my App::Cpan module, I include Local::Null::Logger, a fallback class that fakes the interface of Log::Log4perl. The module is in core, but I don’t intend Local::Null::Logger to ever be user visible.

This relates to my one big hate of Perl: namespaces and filenames are linked because of the way use works. I made that the subject of my 2011 Frozen Perl keynote address.

I was curious how many cuckoos I find, so I wrote a little program to extract the package names and compare them to the file name:

#!perl
use v5.14;
use strict;

use Module::Extract::Namespaces;

LINE: while( <> ) {
	chomp;
	my @namespaces = Module::Extract::Namespaces->from_file($_); 
	if( @namespaces == 1 ) {
		my $file = $namespaces[0] =~ s/::/\//g;
		$file .= '.pm';
		next LINE if /\Q$file\E\Z/;
		}
	
	my $said = 0;
	my %Seen;	
	foreach my $n ( @namespaces ) {
		my $file = $n =~ s/::/\//rg;
		$file .= '.pm';
		next if /\Q$file\E\Z/;
		next if $Seen{$n}++;
		say unless $said++;
		print "\t$n\n";
		}
	print "\n" if $said;
	}	

I got a much longer list than I expected when I ran this against my v5.18.1 installation

% find /usr/local/perls/perl-5.18.1/. -name '*.pm' | perl5.18.1 cuckoo.pl
/usr/local/perls/perl-5.18.1/./lib/5.18.1/App/Cpan.pm
	Local::Null::Logger

/usr/local/perls/perl-5.18.1/./lib/5.18.1/B/Lint/Debug.pm
	B::SPECIAL
	B::OP
	B::SVOP
	DB

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Carp.pm
	DB

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CGI.pm
	Fh
	MultipartBuffer
	CGITempFile

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Class/Struct.pm
	Class::Struct::Tie_ISA

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Compress/Zlib.pm
	Zlib::OldDeflate
	Zlib::OldInflate

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN/Distroprefs.pm
	CPAN::Distroprefs::Result
	CPAN::Distroprefs::Result::Error
	CPAN::Distroprefs::Result::Warning
	CPAN::Distroprefs::Result::Fatal
	CPAN::Distroprefs::Result::Success
	CPAN::Distroprefs::Iterator
	CPAN::Eval
	CPAN::Distroprefs::Pref

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN/HandleConfig.pm
	CPAN::Config

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN/Meta/Requirements.pm
	CPAN::Meta::Requirements::_Range::Exact
	CPAN::Meta::Requirements::_Range::Range

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN/Mirrors.pm
	CPAN::Mirrored::By

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN/Queue.pm
	CPAN::Queue::Item

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPAN.pm
	CPAN::Eval

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPANPLUS/Error.pm
	Log::Message::Handlers

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPANPLUS/Selfupdate.pm
	CPANPLUS::Selfupdate::Module

/usr/local/perls/perl-5.18.1/./lib/5.18.1/CPANPLUS/Shell.pm
	CPANPLUS::Shell::_Base::ReadLine

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/B.pm
	B::OBJECT
	B::Section

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/DB_File.pm
	DB_File::HASHINFO
	DB_File::RECNOINFO
	DB_File::BTREEINFO

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/Encode.pm
	Encode::UTF_EBCDIC
	Encode::Internal
	Encode::utf8

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/IO/Pipe.pm
	IO::Pipe::End

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/IPC/Msg.pm
	IPC::Msg::stat

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/IPC/Semaphore.pm
	IPC::Semaphore::stat

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/IPC/SharedMem.pm
	IPC::SharedMem::stat

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/mro.pm
	next
	maybe::next

/usr/local/perls/perl-5.18.1/./lib/5.18.1/darwin-2level/POSIX.pm
	POSIX::SigAction
	POSIX::SigSet
	POSIX::SigRt

/usr/local/perls/perl-5.18.1/./lib/5.18.1/DBM_Filter.pm
	Tie::Hash

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Env.pm
	Env::Array
	Env::Array::VMS

/usr/local/perls/perl-5.18.1/./lib/5.18.1/ExtUtils/Install.pm
	ExtUtils::Install::Warn

/usr/local/perls/perl-5.18.1/./lib/5.18.1/ExtUtils/MakeMaker.pm
	main
	MY

/usr/local/perls/perl-5.18.1/./lib/5.18.1/ExtUtils/Mkbootstrap.pm
	DynaLoader

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Fatal.pm
	autodie::Scope::Guard

/usr/local/perls/perl-5.18.1/./lib/5.18.1/File/Temp.pm
	File::Temp::Dir

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Getopt/Long.pm
	Getopt::Long::Parser
	Getopt::Long::CallBack

/usr/local/perls/perl-5.18.1/./lib/5.18.1/HTTP/Tiny.pm
	HTTP::Tiny::Handle

/usr/local/perls/perl-5.18.1/./lib/5.18.1/IO/Compress/Base/Common.pm
	U64

/usr/local/perls/perl-5.18.1/./lib/5.18.1/JSON/PP.pm
	JSON::PP::Boolean
	JSON::PP::IncrParser

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Log/Message/Simple.pm
	Log::Message::Handlers

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Math/BigInt/CalcEmu.pm
	Math::BigInt

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Module/Build/Base.pm
	Module::Build::PodTester

/usr/local/perls/perl-5.18.1/./lib/5.18.1/NEXT.pm
	NEXT::UNSEEN
	NEXT::DISTINCT
	NEXT::ACTUAL
	NEXT::ACTUAL::UNSEEN
	NEXT::ACTUAL::DISTINCT
	NEXT::UNSEEN::ACTUAL
	NEXT::DISTINCT::ACTUAL
	EVERY
	EVERY::LAST

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Object/Accessor.pm
	Object::Accessor::Lvalue
	Object::Accessor::TIE

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Pod/Html.pm
	Pod::Simple::XHTML::LocalPodLinks

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Pod/InputObjects.pm
	Pod::InputSource
	Pod::Paragraph
	Pod::InteriorSequence
	Pod::ParseTree

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Pod/ParseUtils.pm
	Pod::List
	Pod::Hyperlink
	Pod::Cache
	Pod::Cache::Item

/usr/local/perls/perl-5.18.1/./lib/5.18.1/sigtrap.pm
	DB

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Term/ReadLine.pm
	Term::ReadLine::Stub
	Term::ReadLine::TermCap
	Term::ReadLine::Tk

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Term/UI/History.pm
	Log::Message::Handlers

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Test/Builder/Tester.pm
	Test::Builder::Tester::Tie

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Text/Balanced.pm
	Text::Balanced::Extractor
	Text::Balanced::ErrorMsg

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Tie/Array.pm
	Tie::StdArray

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Tie/File.pm
	Tie::File::Cache
	Tie::File::Heap

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Tie/Hash.pm
	Tie::StdHash
	Tie::ExtraHash

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Tie/RefHash.pm
	Tie::RefHash::Nestable

/usr/local/perls/perl-5.18.1/./lib/5.18.1/Tie/Scalar.pm
	Tie::StdScalar

/usr/local/perls/perl-5.18.1/./lib/5.18.1/warnings.pm
	DB

/usr/local/perls/perl-5.18.1/./lib/5.18.1/XSLoader.pm
	DynaLoader

/usr/local/perls/perl-5.18.1/./lib/site_perl/5.18.1/Hook/LexWrap.pm
	Hook::LexWrap::Cleanup

/usr/local/perls/perl-5.18.1/./lib/site_perl/5.18.1/Module/Extract/Namespaces.pm
	PPI::Lexer

/usr/local/perls/perl-5.18.1/./lib/site_perl/5.18.1/PPI/XSAccessor.pm
	PPI::Document
	PPI::Document::File
	PPI::Document::Fragment
	PPI::Document::Normalized
	PPI::Element
	PPI::Exception
	PPI::Node
	PPI::Normal
	PPI::Statement
	PPI::Statement::Compound
	PPI::Statement::Data
	PPI::Statement::End
	PPI::Statement::Given
	PPI::Token

One thought on ““Cuckoo” CPAN packages

  1. Neil Bowers

    A few times I’ve been about to create a cuckoo class, then thought “No, Perl5 doesn’t want me to do that”, so I just create a separate module and document it as private / internal. I think sometimes you have to work with the language, even if you don’t agree with it :-)

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>