Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Pragma (more) like Java's 'import'?

by djantzen (Priest)
on May 11, 2003 at 20:52 UTC ( [id://257281]=perlquestion: print w/replies, xml ) Need Help??

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

Is there any way in Perl to do Java-style import statements that allow you to shorten the name of the module you're interested in? For example, in Java you can say either:

import java.util.ArrayList; .... ArrayList al = new ArrayList(); --or-- java.util.ArrayList al = new java.util.ArrayList();

It seems to me that in Perl we generally do the equivalent of the latter, and so end up with statements like Bric::Util::Grp::Asset->new() which to me is a blight on an otherwise nicely written body of code (Bricolage).

I know just enough about import, pragmas, and AUTOLOAD to know it's possible to load a module in such a way that it can be referenced by an abbreviated name, but I don't know of any idiomatic way of doing it. Shouldn't use do this?

TIA, David.


"The dead do not recognize context" -- Kai, Lexx

Replies are listed 'Best First'.
Re: Pragma (more) like Java's 'import'?
by BrowserUk (Patriarch) on May 12, 2003 at 02:07 UTC

    I'm confused by the answers you have received so far in this thread.

    Firstly, if the Module in question is a OO style module, then the only time you need to use the full module name is when you instanciate it:

    my $BUGA = Bric::Util::Grp::Asset->new();

    from that point on, every method you call upon that instance, you call with the syntax:   $BUGA->method( @args );

    Where modules have procedural interfaces (or class methods), then the usual mechanisms for importing individual entrypoints or predefined groups of enterypoints is to use the use Module IMPORT-LIST; syntax (See perlfunc:use.

    A breif look at the Bricolage stuff shows that many of the (many, many!) modules support this syntax for importing individual api's or in groups through the use of group selectors ':standard', ':all' and others.

    So, in answer to your question: Shouldn't use do this?, I would say the answer is: Yes, and it does:).

    Of course, it requires that the modules in question support the syntax, but in the case of Bricolage, it seems that most if not all of them do in as far as it makes sense to.

    As for why the Bricolage documentation doesn't exemplify this, choosing to show every call in the full

    Module::Submodule::SubSubMod::SubSubSubMod::function()

    form (and yes, they really do go that deep!:), I can only speculate at. I did notice that there seems to be an uncommonly large amount of re-use of namespace at different levels of the hierachy, (eg. Asset.pm, Addr.pm, Auth.pm, Contact.pm, Data.pm all appearing twice in the tree, Action.pm appearing 3 times etc.)

    Maybe they use the fully qualified names to ensure distinction. Maybe also, if you import :all from two or more of the individual modules you end up with namespace clashes?

    If this is the case, then using an auto-import-everything-from-this-module routine is only going to compound matters further as you are likely to import similarly named private routines from the modules too.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
      I have a vague suspicion that they might be avoiding imports due to the memory cost - which is significant in a mod_perl environment.

      Makeshifts last the longest.

        I have a vague suspicion that they might be avoiding imports due to the memory cost - which is significant in a mod_perl environment.

        Importing is aliasing. You're not copying the function, but merely aliasing it. All it costs is one symbol table entry.

        Things are different when autoloading takes place, but it depends on the implementation then.

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      Firstly, if the Module in question is a OO style module, then the only time you need to use the full module name is when you instanciate it
      Not necessarily. The constructor Foo::Bar->new is just one example of a class method as opposed to an object method.

      I'm not familiar with Bricolage, so I don't know if this is true in this case, but there may be several class methods, which are concerned with behaviour of the whole class and all objects in it.

      I've also seen more than one type of constructor used in the same class, e.g. Foo::Bar->lookup('quux.db') which returns a whole list's worth of objects.

      My $0.02

      --rinceWind

        I think I dealt with Class Methods when I said?

        Where modules have procedural interfaces (or class methods), ...


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
Re: Pragma (more) like Java's 'import'?
by Zaxo (Archbishop) on May 12, 2003 at 04:47 UTC

    If you just don't like to see deep namespaces, you can use a source filter like POE::Preprocessor, thus:

    use POE::Preprocessor; const BUGA Bric::Util::Grp::Asset use BUGA; my $foo = BUGA->new;

    After Compline,
    Zaxo

Re: Pragma (more) like Java's 'import'?
by broquaint (Abbot) on May 11, 2003 at 22:18 UTC
    It would just be a matter of importing the end part of the package name into main's namespace e.g
    package Foo::Bar::Baz; sub import { $main::{"Baz::"} = $Foo::Bar::{"Baz::"}; }
    However, I don't believe Exporter has this sort of functionality (or any other module for that matter), so you'd have to implement it yourself.
    HTH

    _________
    broquaint

      Make him do it himself? No way, not at Perlmonks! (-:

      package Exporter::End; sub import { my @packages = @_; shift @packages; @packages = (caller)[0] unless defined @packages; foreach my $orig (@packages) { my ($end) = $orig =~ /(\w+)$/; *{"${orig}::import"} = sub { my $pkg = (caller)[0]; *{"${pkg}::${end}::"} = *{"${orig}::"}; } } } 1;

      And then use it like this:

      package Foo::Bar::Baz; use Exporter::End; sub x {print 1}; # ... package main; use Foo::Bar::Baz; Baz::x(); # same as main::Baz::x();

      Or like this:

      package Foo::Bar::Baz; sub x {print 1}; # ... package main; use Exporter::End qw(Foo::Bar::Baz); Baz::x(); # same as main::Baz::x();

      ++, but I'm fairly certian that you want %s there, or even better *s. OTOH, using a * would kill $main::Baz as well as making an alias for the package. (* is better then % because it aliases, rather then coppies, the symbol tables.)


      Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

        but I'm fairly certian that you want %s there, or even better *s
        Assigning with %Foo::Bar::Baz:: will copy the various globs in the symbol table, which should suffice, copying the glob is more efficient and explicitly accessing the glob would do the same job e.g
        ## copy every glob %main::Baz:: = %Foo::Bar::Baz::; ## copy the Baz:: glob $main::{"Baz::"} = $Foo::Bar::{"Baz::"}; ## explicitly reference the glob *main::Baz:: = *Foo::Bar::Baz::
        They all achieve the same goal (roughly), whereas the first example does a complete copy of the symbol table, the second two just create a reference. So one of the second two would be the desired behaviour in this case.
        HTH

        _________
        broquaint

Re: Pragma (more) like Java's 'import'?
by jryan (Vicar) on May 11, 2003 at 23:02 UTC

    It sounds like you want to import all symbols from a package into the current package. You can use a small module like this:

    package Exporter::All; sub import { my @packages = @_; shift @packages; @packages = (caller)[0] unless defined @packages; foreach my $orig (@_) { *{"${orig}::import"} = sub { my $pkg = (caller)[0]; foreach (grep {!/^import|__ANON__|BEGIN|END$/} keys %{"${orig}::"}) { if (defined *{"${pkg}::$_"}) { warn "Warning: symbol $_ already defined in $pkg." } else { *{"${pkg}::$_"} = *{"${orig}::$_"}; } } } } } 1;

    And then use it like this:

    package Foo::Bar::Baz; use Exporter::All; sub x {print 1}; # ... package main; use Foo::Bar::Baz; x();

    Or like this:

    package Foo::Bar::Baz; sub x {print 1}; # ... package main; use Exporter::All qw(Foo::Bar::Baz); x();
(jeffa) Re: Pragma (more) like Java's 'import'?
by jeffa (Bishop) on May 11, 2003 at 22:29 UTC
    This is probably cheating:
    package main; my $al = new ArrayList(qw(foo bar baz qux)); print $_,$/ for @$al; package java::util::ArrayList; sub new {bless[@_[1..$#_]],shift} package ArrayList; use base qw(java::util::ArrayList);

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
Re: Pragma (more) like Java's 'import'? (yes!)
by tye (Sage) on May 12, 2003 at 17:36 UTC

    In Perl6, I suspect you'll solve this problem with code something like:

    my $ArrayList= use Perl::Util::ArrayList; my $a= $ArrayList->new();
    because Larry mentioned that he'd like to have use return the package that was just created (I think he meant/said "package object" not "package name" but that doesn't really change the above code much).

    In Perl5, I solve this problem by having the module be able to export a factory object (for OO modules) and by supporting aliasing of functions during export (for procedural modules):

    my $Widget; use My::Widget::Module( Factory=>\$Widget ); my $dumper; use Devel::Peek( { Dump=>\&DumpSV } ); use Data::Dumper( { Dump=>\&Dumper } ); use My::Module( { Dump=>\$dumper } ); my $flange= $Widget->new(); $dumper->( $flange ); Dumper( $flange );
    Note that you have to write your own sub import to support the above (some of the newer replacements for Exporter also support aliasing of imports, IIRC).

    And, although Perl5 doesn't support my $x= use ..., it does support (but doesn't document) the following rather neat trick:

    my $factory= require My::Object::Module;
    via a module like, for example:
    package My::Object::Module; # ... sub factory { # ... } # ... \&factory; # a 'true' value
    The only thing I don't like about this trick (besides it being undocumented, though that didn't stop me from guessing that it might work) is that you can't pass in any arguments to require like you can with use.

                    - tye
      Well, not directly.
      my $factory = (require My::Object::Module)->(foo => "bar");
      Obviously,
      package My::Object::Module; sub factory { ... } sub fake_import { # ... # ... return \&factory; } \&fake_import; __END__

      Makeshifts last the longest.

      And, although Perl5 doesn't support my $x= use ..., it does support (but doesn't document) the following rather neat trick:
      my $factory= require My::Object::Module;

      ...which you shouldn't use becase that will only work if you can guanantee that you are the only one who will ever require My::Object::Module. This undocumented return value only works the first time require is called. All subsequent requireings of that modules simply return 1.

      D'oh!

                      - tye
Re: Pragma (more) like Java's 'import'?
by benn (Vicar) on May 11, 2003 at 22:35 UTC
    Is this what you want? It's the other way around - from the caller's point of view...
    use Foo::Bar::Baz; local *alias:: = *Foo::Bar::Baz::; print alias->new($a,$b,$c); # Foo::Bar::Baz=HASH(0x123456)

    Cheers,
    Ben

      This will pass alias as the classname to Foo::Bar::Baz::new(), which is not necessarily desired.

      Makeshifts last the longest.

Re: Pragma (more) like Java's 'import'?
by adrianh (Chancellor) on May 24, 2003 at 16:45 UTC

    If all your concerned about is long class names in calling OO code nobody seems to have mentioned the simplest option - just put the class name in a constant subroutine or a variable.

    sub Very::Very::Very::Very::Long::Name::hello { my $class = shift; print "$class says hello\n" }; # old school way Very::Very::Very::Very::Long::Name->hello; # compile time constant sub works fine - but can be confusing to read use constant VVVVLN => 'Very::Very::Very::Very::Long::Name'; VVVVLN->hello; # I tend to just use a variable my $VVVVLN = 'Very::Very::Very::Very::Long::Name'; $VVVVLN->hello;
Re: Pragma (more) like Java's 'import'?
by djantzen (Priest) on May 13, 2003 at 18:45 UTC

    All, thank you for your comments. We had to roll out a new feature on Sunday night and now we're bug hunting so that's the reason for my unfortunate lack of participation in this thread thus far. More to come.... :)


    "The dead do not recognize context" -- Kai, Lexx

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://257281]
Approved by halley
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-19 16:21 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found