This post on p5p is worth repeating:
Johan Vromans wrote:
>>From Ricardo SIGNES > Perl-Critic-Tics-0.002 >
> Perl::Critic::Policy::Tics::ProhibitUseBase :
>
> "use base qw(Baseclass);
>
> You've seen that a hundred times, right? That doesn't mean that
> it's a good idea. It screws with $VERSION, it (temporarily)
> clobbers your $SIG{__DIE__}, it doesn't let you call the base
> class's import method, it pushes to @INC rather than replacing it,
> and it devotes much of its code to handling the nearly totally
> unused fields pragma -- but the multiple inheritence that pushing
> to @INC sets up is not supported by fields."
>
> Is this still true? I thought most of these issues were dealt with.
If they aren't, nobody's reported them.
* The $SIG{__DIE__} issue is fixed.
* I don't know what people are talking about screwing with $VERSION.
* You shouldn't be importing functions from a superclass and nobody's
stopping you from adding a "use Baseclass" if you really want to.
* I've yet to see a practical reason why pushing to @INC is wrong.
If it replaced @INC the same people would be complaining I'm sure.
* Who cares how much code it devotes to fields?
* Who cares if fields doesn't support MI? Does anyone use fields anymore?
Most folks miss the important points:
* It happens at compile time.
* It has error checking.
That its at compile time avoids some nasty circular dependency issues such as...
# File A.pm
package A;
use B;
@ISA = qw(B);
use C;
1;
# File B.pm
package B;
sub foo { 42 }
1;
# File C.pm
package C;
print A->isa("B") ? "Yes\n" : "No\n";
print A->can("foo") ? "Yes\n" : "No\n";
1;
Use base instead and that all works. Yes, C should be using A but I've read a lot of commercial code that just assumes other modules are loaded and its a horrible thing to debug.
* You shouldn't be importing functions from a superclass and nobody's stopping you from adding a "use Baseclass" if you really want to.
True, but it's frustrating to inherit from a base class which might need arguments passed to its import method. There was some discussion about this on P5P and I recall someone suggesting something like this:
use base
'SomeClass',
'SomeOtherClass' => { import => [ qw/import args/ ] };
That would be backwards compatible and get around that limitation.
Re:Importing
drhyde on 2007-08-01T12:16:33
Also import() isn't just used to, umm, import. It's quite a common idiom to use it to pass global settings to a class, such as telling it to put temporary files in a particular place, or changing its default timezone. Those still have their place in OO programming.Even so, I don't consider this to be a problem with base.pm. If I really need to do things like that, the work-around is trivial.
Re:Importing
schwern on 2007-08-01T21:58:19
Here's what I expressed on p5p: 80% of the code and syntax will be devoted to a feature that you use 1% of the time and has a perfectly reasonable work around that everyone understands. Just not worth the extra work/complexity/documentation/bugs.
use base qw(Foo);
use Foo qw(some args);
And isn't it "let's add just one more feature" that got base.pm in this situation in the first place?
* I don't know what people are talking about screwing with $VERSION.
Not that I think it's a problem - but I think folk are referring to base setting VERSION to '-1, set by base.pm' if it's undef.
Adrian (thoroughly in the "liking base" camp)
Yes, C should be using A but I've read a lot of commercial code that just assumes other modules are loaded and its a horrible thing to debug.
What a bogus argument. I would accept this if you had said "I have written a lot of commercial code that just assumes
Now, neither of these two points are what constitutes a "bug", but for some code that should basically be (less the error checking for recursive inheritance)
package base;
use strict;
sub import {
my ($class,$base) = @_;
my $target = caller();
(my $file = $base) =~ s!::|'!/!g;
$file.= ".pm";
require $file;
{
no strict 'refs';
push @{ "$target\::ISA" }, $base;
};
};
1
base.pm has far too many lines and does far too many contortions that I do not want to track down just in case I have a weirdo error that base.pm chooses to suppress. Also, no bad action-at-a-distance occurs by messing with $VERSION and all errors point directly to the source like Can't locate Foo.pm in @INC (... instead of Base class package "Foo" is empty. - in 95% of the cases, that's exactly what's wanted, because somebody misspelled Foo.
(Yes, I'm aware that my code forces every base class to be in a file with a name that matches that base class. If you don't want that, write your own @INC hook or fiddle with %INC.)
Anyway - I started out liking base.pm, but after looking at the source code and having been bitten by UNIVERSAL::require gobbling my (syntax) errors far too many times, I don't want to become one of the people with anecdotal evidence that base.pm has bugs.
Re:Bogus argument
schwern on 2007-08-01T22:02:38
I think we're having a violent agreement. My example about the commercial code was illustrating the importance of inheriting at compile time vs setting @ISA at run time. All the other details of "use base" are orthogonal.
Some people remember to put a BEGIN around setting @ISA (and @EXPORT) but most don't either because they forget or aren't aware.