Three things I'd Change About Perl

Ovid asks about three things you'd change about Perl, which is similar to my standard interview question What are five things you hate about Perl?. I never really answered the question myself, although I did let go of one thing in my Frozen Perl 2011 Keynote: the connection between module names and filenames. Breaking that connection helps with my second thing.

I want first-class classes that I can store in a variable. I want to be able to load multiple and different versions of a distribution. As part of that, I'd want to load distributions, not particular modules. I'd get to the modules through the distribution. I haven't really thought about the syntax for this, though.

I would also be able to load things lexically:

 sub some_sub {
      my $lwp_dist = import( 'LWP', 5.12 );
      my $simple = $lwp_dist->class( 'LWP::Simple' );
      $single->get( $url );
      }

 sub some_other_sub {
      my $lwp_dist = import( 'LWP', 4.45 );
      my $simple = $lwp_dist->class( 'LWP::Simple' );
      $single->get( $url );
      }

I would then also be able to use two different versions in the same scope:

 sub some_other_sub {
      my $dbm_deep_123 = import( 'DBM::Deep', 1.23 );
      my $dbm_deep_223 = import( 'DBM::Deep', 2.23 );

      my $db_old = $dbm_deep_123->new( $file );
      my $db_new =  $dbm_deep_123->new( $new_file );

     ...copy the old to the new...;
      }

But if I can do that, I can create truly anonymous classes without using a package name hack:

 my $class = ...some builtin...;

From there, maybe some of that Moosey stuff makes the stuff inside the class. Once I have the class, I just call methods on it:

 my $instance = $class->new(...);

I think this is probably in Perl 6 with the Mu stuff they added.

The third thing is the boring function signature thing that everyone wants.

7 Comments

It almost sounds like what you want is Ruby :-)

Be careful what you wish for. Ruby does support having multiple versions of a module installed and it turns out to be a nightmare, although the issue is a social one rather than a technical one. It has meant that module authors have ceased to care about backwards compatibility. Minor releases of modules contain major API changes and if you don't like it, well you can just stick with the old version. Managing applications that rely on different versions of a module is painful at best. Packaging such modules and applications for distribution is worse.

This function just looks like a recipe for unmaintainable code and then system administrators contacting hitmen on their developers.

Its interesting how languages focus on programmer conveniences and neglect other parts of a softwares lifecycle which can be just as expensive. Its for this reason alone that i find Java utterly unsuitable for business, as the need to preserve and compile source to objects, gives the operators heart murmurs, versus an interpreted language where there are no such problems.

Arguments as to if the sysadmin should change code can now begin - however 4-5 or even 10 years after the code is written, try finding the developer who wrote it and often even the source code.

Im sure there are other features that could enhance lifecycle as well. Its more a chain of thinking which i dont think is being actively explored due to the popularity of systems like ITIL which fundamentally drive division between developers and operators.

The multiple versions of the same module is an interesting concept, but I agree with grantmclean when he says its a gateway to the can-of-worm farms of nasty problems and impossible to maintain systems.

What I'd much rather is something that captures the intent of such a design and permits a singular distribution to ship several different API versions of the same modules with any given release, giving us the benefit of being able to retain code that is bound to a specific interface without sacrificing the hell that is relying on old buggy code that is possibly filled with security holes.

That way, new interface versions of modules can be shipped with the distribution, and permitting maintenance and updates to the older interfaces while you give people time to transition from one to the other. ( And then you can eventually eliminate support for older API interfaces )

The current approaches I've seen to this are really somewhat frustrating in design, perl5i is using a perl5i::$major:: scheme, and KinoSearch released the old api as KinoSearch1 and then replaced the original package.

My suggestion is something more along these lines:


lib/dist/Some-Package/1/Some/Package.pm
lib/dist/Some-Package/2/Some/Package.pm
lib/dist/Some-Package/current -> lib/Some-Package/2 
lib/Some/Package.pm -> lib/dist/Some-Package/current/Some/Package.pm

this way:


use Some::Package # does what it always did.

# Uses only API 2 of Some::Package as shipped in the Some-Package
# distribution.
use api { version => 2, dist => 'Some-Package' } 'Some::Package'
# code called here is lexically bound to api 2 of Some::Package


So when API 3 is added, code that is deemed only to work with API 2
still uses API 2.


( I'd hate to have to say I want version 1.05 of a module,
and then have to go through all my code and change that version
specification every time they release a security critical
fix ... )


As for the coupling of Module name and file name, I can only
conclude this is a somewhat *good* thing. PHP made the mistake
of being file name oriented and its a perpetual nightmare
trying to support a useable component loading system, and
virtually every major PHP project ships its own file-name-module-name
re-coupling functions.

I wrote anonymous packages that can't conflict with each other for you and put it on https://github.com/rafl/package-anon

The Package::Anon instances you get are blessed hash refs. Those hash refs are actually the stashes new objects are blessed into when calling $package->bless($ref). They represent what you can reach for named classes by doing \%::Some::Class::.

Methods, package variables, and most everything else package-scoped, are stored within globs in those stashes. Have a look at how add_method in lib/Package/Anon.pm works. You can do the same thing to store package variables.

Adding methods is the only thing I've implemented so far, as it was the most useful thing for testing, and because I don't really want to have to much stash manipulation routines in this module. Instead I'll be working on making Package::Stash cope with anonymous stashes and expose that through the Package::Anon module.

Leave a comment

About brian d foy

user-pic I'm the author of Mastering Perl, and the co-author of Learning Perl (6th Edition), Intermediate Perl, Programming Perl (4th Edition) and Effective Perl Programming (2nd Edition).