Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

use Very::Long::Module::Name as Foo;

by liz (Monsignor)
on Oct 14, 2003 at 13:56 UTC ( [id://299107]=perlmeditation: print w/replies, xml ) Need Help??

Why should Python have something that Perl doesn't have?

I wondered so myself after reading The Very::Long::Class::Name problem and all its responses.

broquaint's response (using Package::Alias' knowledge about aliasing stashes at compile time) and bart's response (which is the simple assignment of @ISA) made me come up with YAS (Yet Another Solution). Now I'm wondering whether I should upload this to CPAN or not.

SYNOPSIS
    use as;
    use Very::Long::Module::Name as Foo;
    my $foo = Foo->new;

package as; # Make sure we have version info for this module # Make sure we do everything by the book from now on $VERSION = '0.01'; use strict; # Make sure we can do a source filter use Filter::Util::Call (); # Satisfy -require- 1; #--------------------------------------------------------------------- +------ # Methods needed by Perl #--------------------------------------------------------------------- +------ # IN: 1 class (ignored) sub import { # Initialize the fixer upper subroutine # Obtain parameters # Create the alias specification if appropriate # Return possibly adapted string my $fix = sub { my ($package,$rest) = @_; my $alias = $rest =~ s#\bas\s*((?:\w|\w::\w)+)## ? qq(BEGIN {*{"${1}::"} = \\*{"${package}::"}}) : ''; # Package +::Alias approach # qq(BEGIN {\@${1}::ISA = '$package'}) : ''; # bart's version "${alias}use $package$rest"; }; #$fix # Install the filter as an anonymous sub # Initialize status Filter::Util::Call::filter_add( sub { my $status; # If there are still lines to read # Convert the line if it appears to contain a use statement # Return the status if (($status = Filter::Util::Call::filter_read()) > 0) { s#\buse\s+((?:\w|\w::\w)+)([^;]*)#$fix->( $1,$2 )#eg; } $status; } ); } #import #--------------------------------------------------------------------- +------ __END__ =head1 NAME as - load OO module under another name =head1 SYNOPSIS use as; use Very::Long::Module::Name as Foo; my $foo = Foo->new; =head1 DESCRIPTION This module implements a source filter that allows using of modules wi +th a very long name to be used under another name. This is basically achie +ved by creating a dummy module with the short name that inherits from the +module with the large name and which therefore means that there is a run-time penalty for this feature. =head1 INSPIRATION Inspired by bart's response (http://www.perlmonks.org/index.pl?node_id +=299082) to a thread about long module names on Perl Monks. =head1 AUTHOR Elizabeth Mattijsen, <liz@dijkmat.nl>. Please report bugs to <perlbugs@dijkmat.nl>. =head1 COPYRIGHT Copyright (c) 2003 Elizabeth Mattijsen <liz@dijkmat.nl>. All rights reserved. This program is free software; you can redistribute it and/ +or modify it under the same terms as Perl itself. =cut

Comments welcome. Particularly about whether the stash alias approach, or the @ISA approach is best. And if you think this would be a waste of CPAN space ;-)

Liz

Update:
In this response I describe why this proposal, as well as any similarly functioning module such as Package::Alias, suffer from a serious flaw because they change the global namespace. Needless to say, I won;t be uploading this module to CPAN. Everybody can relax again now ;-)

Replies are listed 'Best First'.
Re: use Very::Long::Module::Name as Foo;
by tilly (Archbishop) on Oct 14, 2003 at 14:18 UTC
    Sorry, but I prefer the existing solutions.

    In terms of complexity to use, all of the proposed solutions, including yours, are about equal. In terms of conceptual difficulty for a Perl programmer to figure out how they work under the hood, yours is significantly more complicated. In terms of avoiding possible conflicts between different modules making use of the feature, I prefer either putting the package name in a variable or a constant to anything that tramples over short global namespaces that other modules don't expect you to trample over.

    Also I like reserving source filtering for when it really buys a lot because I am afraid that, going forward, we will wind up with "interesting conflicts" because different source filters won't cooperate well with each other. (The heuristics which one uses to figure out what is going on don't take into account how the previous one altered Perl.) Traditional Perl modules have much lower odds of conflict.

    In fact a private theory of mine holds that one of the keys to what made CPAN work is that Perl didn't used to lend itself to customization, so code that worked for you probably works without many issues in my environment, and vice versa. This makes sharing easy. Compare, say, to a significant body of C code with heavy use of pre-processor definitions.

      In terms of complexity to use, all of the proposed solutions, including yours, are about equal...

      I disagree with that. I think:

      use Very::Long::Module::Name as Foo;
      is definitely easier to type and to the eye than:
      use as qw(Very::Long::Module::Name Foo); # Package Alias approach

      especially when it comes to parametrized uses. These would all work with my source filter:

      use Very::Long::Module::Name as Foo qw(foo bar baz); # import foo, bar + baz use Very::Long::Module::Name as Foo (); # don't import
      Package::Alias (and Abigail's approach) does not support this.

      ...conceptual difficulty for a Perl programmer to figure out how they work under the hood...

      I also disagree here. If you know about source filters, you will see that the filter is very simple. Creating the source filter involves some strange idioms, I agree, but I can't be blamed for that. And adding some more comments should take care of instructing any other Perl programmers who take a look under the hood.

      Traditional Perl modules have much lower odds of conflict.

      I agree. But I see the source filter merely as a means of achieving the end now, as a prototyping tool, rather than as the way to do such a thing in the long run.

      And so far nobody has commented on the API. So that at least feels right to the people who looked at this so far. I don't think there is a Perl 6 Apocalypse about this, is there?

      Liz

        Your opinions on what is and is not obvious clearly differ from mine. And breaking out the 50 pound sledgehammer of source filters, along with all of TheDamian's heuristics about how to interpret what is valid Perl (which you are quickly obsoleting), along with the potential bugs when TheDamian gets it wrong, doesn't strike me as a conceptually lightweight approach. Even when the piece that you added is simple.

        Now if you want parametrized uses, consider the following (untested):

        package load; use Carp; use strict; sub as { my $pkg = shift; # Set the alias. $_[0] = $pkg; # load the module eval "require $pkg"; die $@ if $@; # import it? shift; if (@_) { unshift @_, $pkg; my $import = $pkg->can("import") or croak("No import available to use"); goto &$import; } } 1;
        This can now be used (assuming no bugs...) as follows:
        use load; Very::Long::Module->load::as my $short => qw(foo bar baz);
        If you prefer a constant approach, that isn't hard to do either.

        In any case the difference in ease of usage between these solutions and a source filter is pretty minor. The difference in potential problems is pretty large. (Note that I am steering towards solutions where you can create any aliases for yourself without trampling on any potential global namespace. That is both deliberate and, I feel, important.)

Re: use Very::Long::Module::Name as Foo;
by demerphq (Chancellor) on Oct 14, 2003 at 14:31 UTC

    IMO source filters are a bad idea. My choices for resolving this in an external module would be (in order of preference):

    use Some::Very::Long::And::Annoying::Package::Name; use constant SVLAAPN=>'Some::Very::Long::And::Annoying::Package::Name' +; push @SVLAAPN::ISA,'Some::Very::Long::And::Annoying::Package::Name'; my $o=SVLAAPN->new();

    Its unlikely I would use the stash approach as that just gives me the heebie-jeebies.

    But this comes to an interesting point. An author of such an annoying package can easily provide the alias themselves... Ie in perl/site/lib/Some/Very/Long/And/Annoying/Package/Name.pm the author could have easily put

    package SVLAAPN; ...

    IOW, the package contained in a file that is used need _not_ be the same as the filename would indicate. A good and common example is Carp::Heavy. There is in fact no such thing. The file perl/lib/Carp/Heavy.pm contains only code for the package Carp. Now this might not be the best example as Carp/Heavy.pm is a behind the scenes kinda thing, but it does illustrate the point nicely.

    In short while this is groovy and cool looking, it isn't perl (really), and it doesnt belong in production code. Nor do I think there is much need for this type of thing. The problem doesnt arise much and it only takes a few lines of code to sort out when it does. So IMO, this is a bit of overkill.


    ---
    demerphq

      First they ignore you, then they laugh at you, then they fight you, then you win.
      -- Gandhi


Re: use Very::Long::Module::Name as Foo;
by Abigail-II (Bishop) on Oct 14, 2003 at 14:40 UTC
    Here's a different way, also using a 'as.pm', but no source filters. Usage:
    use as Name => "Very::Long::Class::Name", args ...;
    And this is the code:
    package as; use strict; use warnings; sub import { my $class = shift; die "Usage: 'use as Name => Very::Long::Class::Name [args...]'" unless @_ >= 2; my $caller = caller (); my ($short, $long) = splice @_ => 0, 2; no strict 'refs'; @{"${short}::ISA"} = $long; eval <<" --"; package $caller; require $long; $short -> import (\@_) if $short -> can ("import"); -- die $@ if $@; } 1;

    This follows a similar syntax as 'use if CONDITION, MODULE => ARGS'.

    Abigail

      This is essentially the same API as Package::Alias, although different under the hood.

      Liz

Re: use Very::Long::Module::Name as Foo;
by broquaint (Abbot) on Oct 14, 2003 at 14:36 UTC
    The problem with a source filter approach is that it can very easily run over program data or conflict with existing filters. Personally, I would've thought a straight-forward import approach would've been easiest e.g
    package allow_as; use Carp 'croak'; sub import { my($pkg, %args) = @_; return unless exists $args{as} and length $args{as}; croak "Symbol table '$args{as}' already exists" if defined *{"$args{as}\::"}; *{"$args{as}\::"} = *{"$pkg\::"}; } 1; =pod =head1 USAGE package Your::Very::Long::Name::Here; use base 'allow_as'; sub import { ## perhaps you want your own import code? $_[0]->SUPER::import(@_[1 .. $#_]); } ## later use Your::Very::Long::Name::Here ( as => 'yvlnh', other => [qw/user parameters perhaps?/], ); =cut
    This doesn't work as globally as your filtering mechanism, but it also follows in the footsteps of Exporter of allowing the user to simply inherit the module to enable aliasing (which may not always be desirable, like the ability to export random methods). Also, the reason I stuck with the aliasing route is that it is much cleaner than simply using @ISA. It means that objects are blessed into the original package and not the inherited alias, which will keep any introspection consistent, saves avoids dispatching every method call, and it really is an alias as opposed to a quick work-around.
    HTH

    _________
    broquaint

      Method calls are cached so it makes no difference what package they are called against. And the constant-or-variable-with-package-name-in-it approach has the same properties as your code FWICT.

      K.I.S.S.

      :-)


      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


        Method calls are cached so it makes no difference what package they are called against.
        Ah yes, I'm forever forgetting that!
        And the constant-or-variable-with-package-name-in-it approach has the same properties as your code FWICT.
        But it's not an alias, it's just a shorter way of referring to a package name (although this does equate to the same thing when calling class methods). It means the difference between referring symbolically to the original package, and referring to the package directly via the alias e.g
        ## accessing a package variable my $path = ${"$var\::Config"}->{'data_path'}; ## vs. my $path = $alias::Config->{'data_path'};
        Ok, so it might be a somewhat contrived, but I think it nicely illustrates that the two approaches are not the same.
        HTH

        _________
        broquaint

Re: use Very::Long::Module::Name as Foo;
by hardburn (Abbot) on Oct 14, 2003 at 16:59 UTC

    . . . bart's response (which is the simple assignment of @ISA) . . .

    I'd like to use this as cannon fodder against those who said modifying @ISA directly is OK here. My argument in that meditation was that directly assigning @ISA is bad because it clobbers any existing values, and that one should always use base instead, if possible. Many posters in that thread noted that nobody else should be messing with your package's @ISA. At the time, I couldn't come up with a good reason why an external source would be playing with your @ISA, but thought there might be a good reason that I hadn't seen yet. Now I have one. Thanks :)

    I'd like to take this opertunity to say na na na, your it, no returns.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: use Very::Long::Module::Name as Foo;
by pg (Canon) on Oct 14, 2003 at 15:20 UTC

    I realized something…

    The real problem is that Perl does not differentiate the concept of ‘package’ and the ‘class’ being contained in the ‘package’. Otherwise, you should not worry to mention the full path of the package, as long as the class name only exists in a single package that you loaded.

    I would expect this go on the right track, once OO is supported in a more natural way in Perl…

Re: use Very::Long::Module::Name as Foo;
by pg (Canon) on Oct 14, 2003 at 14:36 UTC
    I think those solutions provided previously are good enough for now. Although personally I believe, it makes much more sense for Perl to deliver this kind of trivial but essential stuffs as part of the language itself (not as any sort of patch).
      ...it makes much more sense for Perl to deliver this kind of trivial but essential stuffs as part of the language itself...

      I couldn't agree more. But suppose I would find the courage to go into the Perl innards so that this would be possible in 5.10. Wouldn't it then be nice to be able to use that idiom in older versions of Perl as well?

      And vice versa, the "public acceptance" of this module would be a good indication of whether it would make sense to put such a feature in the core Perl itself.

      Liz

Re: use Very::Long::Module::Name as Foo;
by Aristotle (Chancellor) on Oct 15, 2003 at 00:09 UTC
    Your approach isn't transparent: references will be blessed into the shortname package. I chose to use constants in the other thread for this reason.
    $ perl -MO=Deparse -e'Foo::Bar->new'
    'Foo::Bar'->new;
    -e syntax OK
    $ perl -MO=Deparse -e'use constant FB => "Foo::Bar"; FB->new'
    use constant ('FB', 'Foo::Bar');
    'Foo::Bar'->new;
    -e syntax OK

    Note how it compiles to exactly the same code. There is absolutely no chance that it will behave any differently than the original code in any case ever.

    And while it may seem simple, your approach needs some very heavy weaponry to work. It is in gross violation of the "do the simplest thing that can possibly work" principle.

    Makeshifts last the longest.

      As I try not to use indirect object syntax (anymore), I think the approach to define a constant is the most portable way for now. So no argument from me there (anymore).

      It is in gross violation of the "do the simplest thing that can possibly work" principle.

      I don't agree there. I still think my approach is the cleanest from the user's point of view. It doesn't need the definition of any extra variables or constants, which I think are cruft from an API point of view. And therefore, it is the simplest thing that can possibly work in my eyes.

      Under the hood, Perl is already using rather heavy weaponry to DWIM. Constants are one (first create a subroutine, then inline the constant later). Tieing variables is another one. And what about $&? All can be done in other ways, yet everyone likes the fact that they're there if they want to take the performance penalty.

      Personally, I think it would not be a real big issue to implement the "as modulename" feature in the C-code that handles "use" in Perl (which would put the namespace aliasing stuff under the hood there). And I think the effect on compiling would be negligeble (only extra complexity while compiling a "use"). However, the reason I'm not going to pursue this, is the global namespace problem. I don't see a simple solution for making the short name local to the package in which it "defined".

      Liz

      Your approach isn't transparent: references will be blessed into the shortname package.
      shell> perl -le '*a::=*b::; print bless [], "a"' b=ARRAY(0x8107f70)
      Or not. As we can see, a is really just like any other glob alias and so is completely transparent.
      HTH

      _________
      broquaint

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://299107]
Approved by gjb
Front-paged by Enlil
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-03-19 05:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found