in reply to Getting rid of "new"

Gah! You want to keep repeating "Some::Other::Class" and get rid of "new" ?? Of the two, the former is much more annoying than the latter. Module names need to be world-wide unique so they need to be fairly long and nearly self-explanatory. Which makes them lousy things to be repeating all over the place in your code. Especially since it is not uncommon for me to switch module names (either because a module got renamed or because I'm using a different module that provides similar functionality).

I like having names for constructors. new() is often a fine name but I often use other names. For example, Win32::TieRegistry didn't even have a 'new' method at first (it had 'Open' and 'Connect'). I also prefer (in most cases) to allow $obj->new( ... ) so that I don't have to keep specifying the configuration parameters that most classes end up having that boil down to module-user preference (and so should only have to be specified once by each module user).

So I much prefer the model of 'use' module, specifying configuration parameters, and get a factory object that you store in a variable having a nice name that use strict will tell you about mispellings of at compile time (just like use tells you about module name mispellings at compile time and unlike how Class::Name->new( ... ) doesn't tell you about mispellings at compile time).

This is especially nice since Perl's OO implementation usually makes it trivial to provide such factories by just making a global incomplete object for the class that contains the default configuration parameters and then allowing $obj->new( ... ). Then you just make Class::Name->new( ... ) turn into $globalDefaultObject->new( ... ) and you don't have to write special code for initializing default values, just simple code to copy (the configuration) parameters from one object to another.

Even nicer would be giving Perl the ability to have real references to modules (a.k.a. packages) and letting people tell strict.pm that symbolic references to a module/package should be a fatal error. This would have the same types of benefits that many already tout for avoiding symbolic references to variables. But even better is that it would allow multiple versions of the same module to be used by the same script (it would even allow custom implementations of the same module with the same version number, which is more than the complex Perl6 scheme would allow, last I looked) and would simplify custom installation of modules, which also makes development of new modules less frustrating for 'newbies'. I outlined this further at Re: $foo = "Foo::Bar"; $foo->new() works? (factories++).

One inconvenience is that Perl 5 doesn't make it easy for require and use to return these factory objects. You can almost get away with my $q= require Net::CGI; but the default return value is "1" not "Net::CGI" and even if Net::CGI is improved to return a factory, it will only do so the first time it is required. But even better than require is use, because it allows you to specify your desired configuration. A chatterbox conversation with Larry lead me to believe that Perl 6 will support my $Factory= use Class::Name( ... ), and I'm even optimistic that such could be done for Perl 5. But, for now, a good approach is something like:

use Data::Heap::Whatever 1.1 ( \my $Heap, KeepTies => 1, CompactDump = +> 1 ); # ^^^^^^^^^ Factory object gets put into +this lexical variable my $bestScores= $Heap->new( '>', -max => 10 ); my $worstScores= $Heap->new( '<', -max => 10 );

This allows you to get rid of all class methods, which surely makes the interface thinner.

- tye        

Replies are listed 'Best First'.
Re^2: Getting rid of "new" (wrong target; perl6)
by Ovid (Cardinal) on Jul 07, 2006 at 17:55 UTC

    Or you could just use aliased:

    use aliased 'Long::Class::Name::For::Customer'; my $customer = Customer->new; use aliased 'Worker::Class::With::A::Long::Name' => 'Worker'; my $worker = Worker->new; use aliased 'Class::Name::With::Imports::For::Munger', Munger => @impo +rt_list; my $munger = Munger->new;

    Or if you prefer lexicals:

    use aliased; my $Customer = alias 'Long::Class::Name::For::Customer'; my $customer = $Customer->new;

    This works well because the module author doesn't need to provide support for it. aliased pretty much works for any OO module.

    Cheers,
    Ovid

    New address of my CGI Course.

      I was addressing module authors more than module users. That looks like a nice module for when using modules that don't already support factories [well, the last example -- the prior ones would need to be written as Munger()->new( ... ) to meet my best practices but still wouldn't meet my preference]. Note that your module wouldn't work for a module that actually did get rid of all class methods. (:

      Oh, and that last example would need to be use aliased 'alias'; to meet my best practices. I suspect your module doesn't support that, so I doubt I'll be using it until that gets fixed. :)

      - tye        

        Oh, and that last example would need to be use aliased 'alias'; to meet my best practices. I suspect your module doesn't support that, so I doubt I'll be using it until that gets fixed. :)
        To be honest, the name alias conflicts with a function in the module Data::Alias by xmath, which IMO is much more interesting, to get the rights to use the name.

        I wish perl5 had an easy way to import stuff into names of your own choice.

        The &alias subroutine is only exported if you don't specify an import list to aliased. That's because it's from a patch by Schwern and lately he's been thinking that exporting things by default is sometimes OK. Since he's the only person who wanted the lexical aliased functionality and it only gets exported if this functionality is requested, I wasn't too worried about it.

        Cheers,
        Ovid

        New address of my CGI Course.

Re^2: Getting rid of "new" (superfluous reference constructor)--
by demerphq (Chancellor) on Jul 07, 2006 at 15:47 UTC

    and I'm even optimistic that such could be done for Perl 5. But, for now, a good approach is something like:

    use Data::Heap::Whatever 1.1 ( \my $Heap

    That reference constructor there is a nit for me. Why should the user be required to provide it? There is no functional reason that it is needed. The import routine should get an alias to the whatever was passed in so I cant really see a reason for it.

    Sorry, but I've encountered this design choice a lot (DBI does it somewhere iirc) and it always kind of irritates me as it seems to me to be so unperlish.

    ---
    $world=~s/war/peace/g

      An alternative:

      use Data::Heap::Whatever 1.1 ( Factory => my $Heap, ...

      But the passing of a reference has two purposes:

      1. It lets us reliably distinguish between an option name and a variable being passed in to receive a factory, thus allowing the more stream-lined usage
      2. It makes the fact that $Heap will be modified explicit, serving as a form of documentation

      I don't have a strong preference (other than wishing use could return a factory), though.

      - tye        

Re^2: Getting rid of "new" (wrong target; perl6)
by Anonymous Monk on Jul 11, 2006 at 08:34 UTC
    use Data::Heap::Whatever 1.1 ( \my $Heap, KeepTies => 1, CompactDump = +> 1 ); # ^^^^^^^^^ Factory object gets put into +this lexical variable my $bestScores= $Heap->new( '>', -max => 10 ); my $worstScores= $Heap->new( '<', -max => 10 );
    $Heap is scoped to the implicit BEGIN block.

      Thanks. Drat, I thought I'd used that before. So you need to declare the variable outside of the use statement (which is clearer and how I'd normally write such code anyway).

      - tye