http://qs1969.pair.com?node_id=419421

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

I was going to release a module named "Aliased" which would alias long class names to short ones. However, it's only for OO modules , it sort of alters compile-time behavior so one might think of it as a pragma, and "class" is not a keyword. Thus, I could do this:

use class 'My::Company::Namespace::Customer'; use class 'My::Company::Namespace::Preferred::Customer', as => 'Prefer +red'; my $cust = Customer->new; my $pref = Preferred->new;

My immediate reaction was "no!", we don't want to do that. Then I realized I couldn't think of a reason why. Can you? I certainly don't want to release that and make people mad (though David Wheeler pointed out that "class" doesn't indicate that anything's getting exported to the current namespace).

Side note: the "as" key in the import list is important because there's a separate "import" key in case you need to pass args to the module's import() method.

X-posted to my use.perl journal and to the module authors mailing list.

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Module Naming Dilemma
by gaal (Parson) on Jan 04, 2005 at 23:12 UTC
    How about coding like this?

    our $Customer = 'My::Company::Namespace::Customer'; our $Preferred = 'My::Company::Namespace::Customer::Preferred'; my $cust = $Customer->new; my $pref = $Preferred->new;

    This isn't too bad from a usability perspective. It requires no cleverness to get the correct first arguemnt to the two new subs. It might make updating your code to use a subclass a little easier.

    Variations on this idea: a constant. Or a sub that decides at runtime which classname to return.

      gaal++, that is quite right. People often forget that class names are just package names, and package names are strings. Which means they can be stored in scalars.

      One of the patterns I use a lot is Strategy, in which you typically select (programmatically) between several strategy classes to implement some piece of your application. One of the nice things about Perl is that class names are ordinary objects. So I can do things like this:

      use Output::Console; use Output::Tk; my $output_strategy = -T STDOUT ? 'Output::Console' : 'Output::Tk'; my $output = $output_strategy->new();
      The same principle could be used to shorten long class names.

      I prefer having a variable too. I'd even do

      our $Customer = My::Company::Namespace::Customer::; # <--- trailing +colons!
      to make sure that I didn't mistype the class name. (See Re: Capitalized subroutine names and packages.)

      Variables has the extra advantage of expanding right:

      # Hi, this is written by me, the maintainer. do_something_with_class(Customer => \&callback); # Oops, I missed that Customer really was a # subroutine mimicing a bareword. *That* took a # while to figure out, huh!
      Generally, I don't like to make stuff look like something it isn't.

      ihb

      See perltoc if you don't know which perldoc to read!
      Read argumentation in its context!

Re: Module Naming Dilemma
by PodMaster (Abbot) on Jan 04, 2005 at 22:20 UTC
    What do you mean sort of alters compile-time behaviour?

    My first reaction is also "No!" because so far it sounds similar to modules such as

    and/or
    use Module::Blah qw[ yada yada ]; use constant Boing => 'Module::Blah';

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.

      Can you suggest a better name? I need something short and sweet. As for "sort of alters compile time behavior", it doesn't really, but it has the appearance of doing so. Thus, a pragma named "class" seemed reasonable. The name bothers me, but I honestly can't think of a serious objection to it. "aliased" might also be good:

      use aliased "Some::Obnoxiously::Long::Name::For::A::Customer"; my $cust = Customer->new;

      Cheers,
      Ovid

      New address of my CGI Course.

        How about namespace::not? namespace::lite? oo::a? Now that you've divulged how it works, maybe you can contact the author of namespace and add an option for it to work like your implementation? or just go with namespace::lite?

        MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
        I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
        ** The third rule of perl club is a statement of fact: pod is sexy.

Re: Module Naming Dilemma
by jdporter (Paladin) on Jan 04, 2005 at 22:05 UTC

    Hmmmm... I did something along the same lines, a long time ago. Lemme see if I can find it...

    Ah, here it is - Exporter::PkgAlias.

    Unfortunately, it seems I never uploaded it to CPAN. I should remedy that...

      Your module really is aliasing a namespace, yes? Mine just creates a subroutine that returns the package name and inserts it into the calling namespace (after doing some stuff to handle loading and importing.)

      The important thing here is that the module name be very short to actually make it worthwhile to use. It's also been pointed out that this makes it easier to use a module that's merely been renamed.

      Cheers,
      Ovid

      New address of my CGI Course.

        Well, in answer to your question... I assume you're aware of the general restrictions/caveats on both top-level namespaces and lower-case namespaces. You should discuss your naming idea on comp.lang.perl.modules, and then on modules@perl.org which is where the PAUSE police lurk. I don't know who has the authority to issue a pragmatic module name; probably p5p or the pumpking.

        Wouldn't it be simpler for
        use class 'My::Company::Namespace::Customer';
        to do the import and just:
        @Customer::ISA = 'My::Company::Namespace::Customer';

        On second thought, I think I prefer your way. Less side-effects that I can see.

        I hope that you've documented (and possibly checked!) that your aliases can't contain things like :: in them.

        If I didn't know how it was implemented, I could easily see myself being bitten by that.

        (Note: I happen to agree with Perrin's response in your diary. I happen to dislike the idea and wouldn't use it. But then again, I don't have to.)

Re: Module Naming Dilemma
by stvn (Monsignor) on Jan 05, 2005 at 01:23 UTC

    IMO, class is a really bad name for it. It is really just aliasing a class name, and in no way is it involved in the declaration or creation of classes.

    As for the "lowercase pragmas are forbidden", I think that's silly. If you don't want to use it, don't download it, simple enough.

    As for a better name, well since Alias is taken, and what you are doing is actually aliasing the class name, maybe Class::Alias especially if it is only for OO. A few others which come to mind are: shorten, rename and this (as in use this 'Long::Class::Name' => as => 'Short';). Eah, maybe not.

    -stvn
Re: Module Naming Dilemma
by xdg (Monsignor) on Jan 04, 2005 at 23:41 UTC

    I like the concept. I took a similar, though slightly different, approach in Math::Random::OO, where I have several subclasses and didn't want to type out the full constructor each time. In short, I have my main module export a "factory function" (better names welcomed) that encapsulates a call to the constructor. So you can do this:

    use Math::Random::OO qw( Uniform UniformInt Normal Bootstrap ); $uniform = Uniform(-1,1); $uni_int = UniformInt(1,6); $normal = Normal(1,1); $boot = Bootstrap( 2, 3, 3, 4, 4, 4, 5, 5, 5 );

    I did it by writing a quick custom import function like so (though as I post it, I see that I'm not checking for certain errors -- grrr -- bad style, slap on the wrist for me.):

    sub import { my ($class, @symbols) = @_; my $caller = caller; for (@symbols) { no strict 'refs'; my $subclass = "Math::Random::OO::$_"; eval "require $subclass"; *{"${caller}::$_"} = eval "sub { return ${subclass}->new(\@_) }"; } }

    Your module sounds like a generalization of this approach, albeit still requiring the call to new. As for names, I'd prefer if your module were named "Alias" or something similar, as what you're doing is aliasing, not defining or altering a class. How about some syntax like this:

    use Alias 'My::Long::Class::Name' => 'ShortForm'; use Alias [ 'My::Long::Class::Name', @options ] => 'ShortForm';

    (update:Alias is already used, so I guess it has to be something else.)

    The first example is simpler than than using "as" as a keyword. The second keeps the real name and options together and still is suggestive that, in the end, you're aliasing it to ShortForm.

    update:I wasn't familiar with Package::Alias and namespace, both look like they do pretty much the same as what I've got above.

    update 2:I guess the advantage of what Ovid's trying to do compared to, say, Package::Alias is that he gets it done in a single function call, rather than a "use" and an "alias" afterwards. May I humbly suggest "Nickname" as the module name, with a syntax like I suggest above for brevity in the standard case with no extra import options?

    use Nickname 'My::Long::Class::Name' => 'ShortForm'; use Nickname [ 'My::Long::Class::Name', @options ] => 'ShortForm';

    -xdg

    Code posted by xdg on PerlMonks is public domain. It has no warranties, express or implied. Posted code may not have been tested. Use at your own risk.

Re: Module Naming Dilemma
by BrowserUk (Patriarch) on Jan 05, 2005 at 02:00 UTC

    I also think that using the pragma 'class' for this purpose is a very bad idea.

    Partly because it implies the aliasing would only work for classes, when it would work for any package.

    Partly because a 'class' pragma could be used for so many other, more specific purposes.

    Maybe package?

    use package Long::Unweildy::Module::or::Package, as => 'LUMP';

    Or minym. As a non-word it is unlikely to clash with any other usage, but the derivation should be quickly and easily grasped by anyone encountering it for the first time.

    use minym 'LUMP', for => 'Long::Unweildy::Module::or::Package';

    You might even become responsible for giving the language a new word :)


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.

      package is a reserved word, so I won't use that. Second, this module only works for classes. It doesn't work for non-OO stuff. The reason is pretty straight-forward. To make it work for a procedural module, the syntax would be like this (picking "aliasing.pm" as a nice alternative):

      use aliasing "Really::Long::Package::Name"; print Name::some_func();

      In order to get that to work, I need to alias typeglobs together like namespace does. However, by literally pulling things from one namespace to another, I would break a lot of code that is expecting a particular namespace (whether or not it should is an argument for someone else.) Thus, the principle of least surprise tells me that I need this to work only for classes and I do this by simply providing a subroutine that returns the original class name.

      Further, from my experience with code that's very similar to this, packages with long names are either procedural code that exports what I need (hence I don't usually use the package name after the first usage) or classes for which the aliasing code makes sense. I don't typically find cases where I need to do this:

      my $foo = Really::Long::Package::Name::some_func();

      Of course, your mileage may vary.

      Cheers,
      Ovid

      New address of my CGI Course.

      ...the derivation [of minym] should be quickly and easily grasped by anyone encountering it for the first time.

      Everyone except me, I guess... Care to enlighten me?

        1. pseudonym: false name.
        2. synonym: same (or similar) word (name).
        3. antonym: opposite word (name).
        4. anonym: anonymous name.
        5. minify: To make smaller or less significant; reduce.
        6. minym: minimal name? :)

        Examine what is said, not who speaks.
        Silence betokens consent.
        Love the truth but pardon error.
Re: Module Naming Dilemma
by sgifford (Prior) on Jan 05, 2005 at 03:13 UTC
    I think the name class is too general for the very specific thing you're doing, though the syntax is nice. shortname or aka would be short and intuitive names that would work just as well while being much more specific.
      ... or aka ...

      Nice one, I like that :)

      -stvn
Re: Module Naming Dilemma
by demerphq (Chancellor) on Jan 05, 2005 at 01:04 UTC

    I like it Ovid. I think if people dont like you taking the 'class' pragma then maybe 'classname' might be more tolerable? I do agree it seems nicer as a pragma for some reason.

    ---
    demerphq

Re: Module Naming Dilemma
by kscaldef (Pilgrim) on Jan 05, 2005 at 20:35 UTC

    I like this idea, but I'm not so crazy about it only working for OO modules (although I understand why it does). Typically I only call new() a small number of times and usually typing the full module name doesn't bother me much.

    What does bother me is typing a long module name over and over for every subroutine of a non-OO module. Of course, exporting does address this, but I find that code that makes extensive use of exported subroutines is hard to read because I have to keep bouncing up to the top of the file to figure out where anything is defined (assuming they are good programmers and explicitly imported, rather than implicitly, in which case things are completely hopeless). In cases like this, it would be nice to have a short way of referring to the subroutines, but without losing all context.

Re: Module Naming Dilemma
by SolidState (Scribe) on Jan 06, 2005 at 15:08 UTC
    Hi Ovid,

    I'm not going to comment on the name - I'm lousy with names :-) But I have to wonder about your motivation for writing this module - what's the purpose?
    If a module is completely OO, you should be able to write the long name only once - when you call new() (or if you call new() several times, save the long name in a variable, as Gaal suggested). Afterwards, all the data and methods should be accesible using $object->method(), for example. Isn't that what OO is all about?

    There was a discussion about this a while ago which started with a question I sent to the Israe.pm mailing list: http://perl.org.il/pipermail/perl/2004-December/006493.html

    From what was said, I'm pretty convinced that you don't need a module such as the one you've written for OO modules. Am I wrong?

Re: Module Naming Dilemma
by Tuppence (Pilgrim) on Jan 07, 2005 at 14:26 UTC

    First off, I love this module and would not enjoy writing large OO codebases in perl half so much without it.

    I have nothing to add as far as naming goes, I like Aliased myself. *shrugs*

    I hated the as at first, but then reading your reasoning I decided that I'm just stuck up and am used to The Way Things Are. Although I have to say that any self respecting OO module should not be using import()... but maybe I'm just not twisted enough yet.

    For the actual useful bit of my post, have you considered dieing if the aliased name already exists in the target namespace? That would stop use Aliased 'My::Foo::Bar'; and use Aliased 'My::Bar::Bar'; from being able to trample one another and have there be no clue until the test suite breaks

Re: Module Naming Dilemma
by legato (Monk) on Jan 10, 2005 at 19:38 UTC

    I found myself needing time to think on this one, and I'm glad I took it. After reading this, and all the replies thus far, I also will speak against the use of class in favor of an alternative (which I'll get to in a moment). The reasons:

    1. I realize that the desire for a succinct name means toplevel is a given, but there is no need, IMHO, for using the all-lower version. Thus, Class would be preferable to class
    2. But, the word 'Class' has very specific connotations. From a learning point of view, I don't think it is immediately obvious what "use Class" does, and I can see it being confused (by a newbie, for example) with just plain use, and I don't think it makes it sufficiently clear that we using a module named "Class" to do the work.
    3. What you're really doing is offering the opportunity to use a shorter class name, not use a class in general, as "Class" or "class" would imply.
    Considering these things, I think any form of class would be out. What would I suggest? How about Shorter? I think it reads well:
    use Shorter 'My::Company::Namespace::Customer'; use Shorter 'My::Company::Namespace::Preferred::Customer', as => 'Pref +erred';

    Anima Legato
    .oO all things connect through the motion of the mind

      Actually, after quite a bit of debate here and elsewhere, I went with the name aliased. You can go ahead and try it out. I'm already using it in production code and it works just fine.

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Module Naming Dilemma
by Anonymous Monk on Jan 05, 2005 at 12:06 UTC
    I'd say, just do it. I've given up on the incomprehensible, non-open "modules@perl.org" years ago. Just upload the module to CPAN and watch what the community thinks of it.
Re: Module Naming Dilemma
by Anonymous Monk on Jan 06, 2005 at 16:48 UTC
    Why not just use a GLOB reference alias?. This will make package Bar works as an alias for Foo:
    *Bar:: = \*Foo:: ;
    Here's a sample:
    package Foo ; sub new { bless {} } sub test { print "TEST> [@_]\n" ; } package main ; *Bar:: = \*Foo:: ; my $foo = Foo->new() ; $foo->test(123) ; print "$foo\n" ; my $bar = Bar->new() ; $bar->test(456) ; print "$bar\n" ;
    Output:
    TEST> [Foo=HASH(0x1a4ece4) 123] Foo=HASH(0x1a4ece4) TEST> [Foo=HASH(0x15d53dc) 456] Foo=HASH(0x15d53dc)
      Doing that you have altered the global namespace. If you were to use this in a module then some one could potentialy overwrite another class used in their code or in another module without ever knowing it. Ovid's and gaal's ideas are both compleatly isolated.
      In short your begging to get bit by this code if it's used in production.