http://www.perlmonks.org?node_id=630996

Ovid has asked for the wisdom of the Perl Monks concerning the following question:

A long time ago, Matt Trout mentioned that he's started using aliased a bit and wanted a feature like this:

    use aliased 'Our::Code::*';

That would be conceptually equivalent to the following Java code:

    import Our.Code.*;

Now imagine you have a directory structure like this:

lib/Our/Code/Customer.pm lib/Our/Code/Datacenter.pm lib/Our/Code/Item.pm lib/Our/Code/Office.pm lib/Our/Code/Order.pm lib/Our/Code/Server.pm lib/Our/Code/Server/Dedicated.pm

The above 'aliased' line would give you aliases like this:

use aliased 'Our::Code::*'; my $cust = Customer->new; my $datacenter = Datacenter->new; my $item = Item->new; my $office = Office->new; my $order = Order->new; my $server = Server->new; my $ded_server = ServerDedicated->new; # unsure of this

Traditionally, that would be something like this:

use Our::Code::Customer; use Our::Code::Datacenter; use Our::Code::Item; use Our::Code::Office; use Our::Code::Order; use Our::Code::Server; use Our::Code::Server::Dedicated; my $cust = Our::Code::Customer->new; my $datacenter = Our::Code::Datacenter->new; my $item = Our::Code::Item->new; my $office = Our::Code::Office->new; my $order = Our::Code::Order->new; my $server = Our::Code::Server->new; my $ded_server = Our::Code::Server::Dedicated->new;

Needless to say, you can see which one folks might like.

Of course, the devil's in the details and I think a module other than aliased would be called for with this experiment. There would also have to be customization options. For example, I think by default it shouldn't use those modules until the alias is actually invoked. Also, by default, we'd want to ensure that only one directory structure is searched and classes loaded from that directory. We might want descending into subdirectories to be optional. One also might want to be able to load and alias all classes in the format Our::Code::O*.

The biggest objection I expect to hear from folks is "mysterious action at a distance is bad!" I can understand that point and I would have raised it myself a long time ago, but I've been around the block long enough to realize why this works for Java so well: after you've been working on your business code long enough, you know what's in lib/Our/Code/*. Of course, it will have issues when you try to do this with lib/Our/Code/DateTime.pm in there. I think a CHECK block might help, not to mention invoking the alias should check if there's a competing entry in %INC. For example, with Our::Code::Order:

sub Order { my $class = 'Our::Customer::Order'; if ( exists $INC{'lib/Order.pm'} ) { # die and noisily complain about a conflict } # load the class if not loaded return $class; }

Unfortunately, whether the class method call dispatches to the namespace or would invoke the alias would depend on how the code was organized. This could be the biggest problem.

I have enough sympathy for the 'action at a distance' argument and a firm enough belief that this is different enough from aliased that the experiment definitely deserves to be in a different namespace.

Side Note: It's also worth nothing that there's a broken import module on the CPAN and it hasn't been updated in 8 years.

Do you have suggestions or comments about such a module's usefulness or implementation? What namespace would be good? How would you get around the DateTime/Our::Code::DateTime problem?

Update: Wow. That was quick. I was having misgivings about this idea, but now I might just drop it completely.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: A Perl Version of Java's import
by jhourcle (Prior) on Aug 07, 2007 at 13:12 UTC

    Although I agree that it could be problematic, and might not be 'Best Practices' for many types of code, the general concept could have its uses.

    I would prefer instead of handling this by moving things into the main namespace, that you instead force a qualification:

    use aliased 'My::Company::Namespace::*' => 'MCN';

    Which would then allow you to call the packages in "My::Company::Namespace" with the alternate prefix "MCN::"

    You could then import/alias multiple namespaces, and just give them different aliases.

Re: A Perl Version of Java's import
by ForgotPasswordAgain (Priest) on Aug 07, 2007 at 10:23 UTC

    I like the idea. I think it should be kept as minimal as possible, though - not 'Our::Code::O*' just 'Our::Code::*'.

    I'm not sure about the import part. On the one hand, I want it to just be like a shortcut for a namespace, so not do an import; but on the other hand, that would be really messy to do the import at the last minute when you actually use a module from that namespace. I think you also have a problem of it not just being new that can be used, as some modules can use other names, and also there are package variables. I'm not sure how Java deals with package variables and namespaces.

    And the last question about resolving DateTime versus Our::Code::DateTime, how does Java deal with that? Is it like putting the namespace at the beginning of @INC?

      Java deals with this by refusing to import any classes which conflict with other classes. Perl's dynamic nature makes this rather difficult to guarantee. This is particularly troublesome because authors might dynamically build a class at runtime, populate the namespace but not add an entry to %INC, thus causing mysterious bugs when only an %INC entry is relied upon when you actually need to check for the existence of a given namespace.

      I can work around some of this, but some of it would be in the hands of a programmer to be careful. I think this is the biggest drawback to this module. However, the question is whether or not this will prove to be a prevalent problem in practice, as opposed to theory. I've seen people refuse to use code whose philosophy they theoretically disagree with even when the reality is far less problematic than it's made out to be.

      Cheers,
      Ovid

      New address of my CGI Course.

Re: A Perl Version of Java's import (lexicals > globals)
by tye (Sage) on Aug 08, 2007 at 03:48 UTC

    I, like many careful programmers, shy away from globals. Do some searching if you don't already know why.

    I seem to be in a small minority in disliking global package names. I wish perl supported use strict 'packages'; which would make it a fatal error to use a symbolic reference to a package.

    In the full implementation, this requires defining a new type of reference, a (non-symbolic) ref to a package. But you can get many of the benefits without waiting for the full implementation.

    Now, modules on CPAN need nice, long, specific, unique names. And the location where they are installed (locally) usually matches those long names (and for good reason). So I'm just fine with mentioning the long name once in order to tell Perl where to find the local copy. But you should never mention it again.

    The best way to prevent name conflicts is to use lexicals instead of globals. That is one reason people suggest open my $log, ... over open LOG, .... And the best way to deal with modules is the same, except that Perl doesn't yet support making this easy all of the time.

    So Perl code should look more like:

    my $Customer= load Acme::Business::Manufacturor::Customer; ... my $cust= $Customer->new( ... );

    No more global package names being thrown all over your code. No need to make hackish (global) copies of symbol tables to do it, either.

    So, for the scenario presented, the better interface would be:

    my %BusMod= loadAll "Acme::Business::Manufacturor::*"; ... my $cust= $BusMod{Customer}->new( ... );

    So then you don't have globals, can be introspective and discover exactly which modules were loaded, etc.

    Now patch Perl (probably Perl 6) so __PACKAGE__ returns a non-symbolic reference to the current package (which stringifies to the package name), so require returns that (by default but with a way to override that), and then the real power comes in. It allows me to have a slightly hacked copy of a module in a different location and I can use both copies of the same module at the same time. I wrote more about that in some node long ago.

    Ah, well, that probably doesn't convey the idea all that well, but I thought it worth throwing out again in the context of this feature idea.

    - tye        

      Among Java people, it is common sense not to load .*, although in practice some people do.

      Agree with you. The OP should really gain a better understanding of other languages before borrow.

      As a matter of fact java gurus only import precisely what they need, they are prond of their exact knowledge of the location of each class.

      What has been suggested in the OP is clearly a stupid idea.

A reply falls below the community's threshold of quality. You may see it by logging in.