Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: AbstractClass

by merlyn (Sage)
on Dec 02, 2000 at 07:51 UTC ( [id://44549]=note: print w/replies, xml ) Need Help??


in reply to AbstractClass

I dunno if Schwern is listening in at the Monestary, but Class::Virtual showed up a few days ago, about a day before you posted this. Odd.

-- Randal L. Schwartz, Perl hacker

Replies are listed 'Best First'.
(tye)Re: AbstractClass
by tye (Sage) on Dec 02, 2000 at 10:02 UTC

    If Schwern was listening, then he wasn't paying very close attention. His module requires each subclass to call a check function directly. Not as nice as many of the methods already posted here.

            - tye (but my friends call me "Tye")
      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).

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://44549]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-03-29 09:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found