Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
No, I wasn't listening, this is my first time really looking at PerlMonks. I was in the middle of mucking about with Tie::Cache::LRU and found myself writing a virtual base class and all these enforcement methods and such. So rather than make a one-off (heavens, no!) I slapped together Class::Virtual.

So first off, Class::Virtual *doesn't* require each subclass to call a check function directly (although re-reading the documentation, I can see why one would think that. Will correct.) The check methods are there for code auditing purposes, reporting, internal use and subclasses of Class::Virtual (as we'll see in a moment). I'll change the docs to de-emphisize them and emphisize the real purpose of the module.

The major difference I can see between Class::Virtual and AbstractClass is C::V does its work at run-time whereas AC works at compile-time. C::V waits until you actually call an unimplemented virtual method before it yells. This might seem silly (since it would have blown up anyway) but it does provide a more informative error. Also, doing the checks at compile-time would cause half my modules to blow up (being the poster boy for method auto-generation that I am). However, not to be outdone...

package Class::Virtually::Abstract; use base qw(Class::Virtual); use Carp::Assert; assert( prototype('CORE::bless') eq '$;$' ); sub bless ($;$) { my $class = $_[1] || caller; if( grep { $_ eq 'Class::Virtually::Abstract' } @{$class.'::ISA'} +) { confess("Connot bless objects into abstract class $class"); } else { CORE::bless(shift, $class); } } sub import { shift; my $base = caller(); *{$base.'::bless'} = \&bless; *{$base.'::import'} = sub { my $class = shift; return if $class eq $base; foreach my $missing_meth ($class->missing_methods) { require Carp; Carp::croak("Class $class must define $missing_meth for cl +ass ". "$base"); } $class->SUPER::import(@_); }; 1; }
That should emulate the compile-time behavior of AbstractClass and its mucking with bless(). (BTW Your prototype is wrong). And feel free to steal the closure trick to generate the import() instead of the eval(). I can flesh this out an ship it with Class::Virtual if you'd like.

So, digging into the internals... a few things bother me about AbstractClass. First, it hijacks import(). Why should an OO module need an import() routine? Well, AbstractClass needs one. Lots of hybrid OO/functional modules need it (Class::Fields for one). Its too important to take away.

Another problem with the import() route is its brittleness. Consider the following...

package Foo; require Some::Abstract::Class; @ISA = qw(Some::Abstract::Class);
Ooops. And this is a perfect valid and common, way of subclassing which defeats AbstractClass. Consider this, too...
package Foo; use base qw(Some::Abstract::Class);
base.pm does not call import() (and rightly so). AbstractClass defeated.

Another, @ABSTRACT_METHODS bothers me. Magical global variables bother me, doubly so in OO contexts. Triply so when you start putting this magical global into other packages. Maybe if you put it into @{$base.'::__ABSTRACT_METHODS'} or something. I take the class data route instead.

Overriding bless... I haven't decided if that's Evil or not. I'd rather define a default new() method that does the same thing. Besides, even if you do manage to generate an object from a virtual class, its going to explode the first time you use it.

Another, with AbstractClass, SomeAbstractClass->can("some_virtual_method") returns false. With Class::Virtual it returns true (but if you try to use the method returned it will explode). I guess this is a design decision.

I don't totally understand why AbstractClass doesn't work with MI, but Class::Virtual doesn't have any problem (god forbid, I can't live without MI).

Finally, in the Class::Virtual scheme, virtual base classes are subclasses of Class::Virtual. I like this because of its synchronicity and because it allows the behavior of Class::Virtual to be altered (as for Class::Virtually::Abstract).


In reply to Re: AbstractClass by Anonymous Monk
in thread AbstractClass by tilly

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-03-28 21:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found