Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Perl, is there any harm in creating a subroutine with the same name as a package?

Say I have a package called My::Pkg, and that package has a ->new(...) class method to instantiate new objects:

package My::Pkg;

sub new {bless {@_[1..$#_]} => $_[0]}

Is there any harm in defining the following subroutine:

sub My::Pkg {@_ ? My::Pkg::new('My::Pkg', @_) : 'My::Pkg'}

So that someone could write:

my $obj = My::Pkg one => 1, two => 2;

Rather than:

my $obj = My::Pkg->new(one => 1, two => 2); # which still works, but is longer

I like the terseness of the package-named-constructor-subroutine method, but I am interested to know if there are any hidden gotchas to this technique that I have not thought of.


Update:

Inheritance works correctly, as shown by the example here:

{package a; sub new {say "a::new [@_] ", $_[0]->init}}
{package b;    our @ISA = 'a'; sub init {"(b::init [@_])"}}
{package a::b; our @ISA = 'b';}

sub a::b {print "absub [@_], "; 'a::b'}

# a::b() called with no args, returns 'a::b', which then becomes 'a::b'->new(...)
a::b->new;            # absub [], a::new [a::b] (b::init [a::b])
a::b->new(1, 2, 3);   # absub [], a::new [a::b 1 2 3] (b::init [a::b])    

# no call to `a::b()` but otherwise the same:
'a::b'->new;          # a::new [a::b] (b::init [a::b])
'a::b'->new(1, 2, 3); # a::new [a::b 1 2 3] (b::init [a::b])

new a::b::;           # a::new [a::b] (b::init [a::b])
new a::b:: 1, 2, 3;   # a::new [a::b 1 2 3] (b::init [a::b])

Interestingly the only thing so far that is different is that the following 2 lines become syntax errors:

new a::b;
new a::b 1, 2, 3;

Which is a syntax error for the same reason some_undefined_sub some_defined_sub; is one.

If the new subroutine is defined, it is parsed as new( a::b(...) ) which is normal for two adjacent bareword subroutines.

Personally, I am ok with new a::b becoming a syntax error, the unambiguous version new a::b:: will always work as tchrist helpfully points out below.

like image 846
Eric Strom Avatar asked May 24 '11 20:05

Eric Strom


1 Answers

That’s precisely why

$thingie = new Some::Class one => 1, two => 2;

or

$thingie = new Some::Class::
               one => 1,
               two => 2,
           ;

exists, so just use that.

But yes, I think you will get yourself into a whole slew of troubles, since I am the only person in the world who bothers to package-quote. I don’t have time right now to dig through my old problem-testing code, but I am pretty sure this will eventually make you cry if you go down the road you’re speaking of.

like image 132
tchrist Avatar answered Oct 21 '22 10:10

tchrist