Stevan Little <[EMAIL PROTECTED]> writes:

> Hello all.
>
> I would like to propose that class methods do not get inherited along
> normal class lines.
>
> I think that inheriting class methods will, in many cases, not DWIM.
> This is largely because your are inheriting behavior, and not state
> (since class attributes are not inheritable). Let me explain in more
> detail.
>
> Let's start by making a very basic definition of an *object*,
> ignoring any implementation details or specifics.
>
>    object == state + behavior
>
> This statement assumes that *objects* at their core are a unique
> state coupled with a collection of behaviors to act upon that
> particular state. Of course we are ignoring all the other class/meta/
> inheritence junk for now.
>
> To take away the behavior, and only be left with state would degrade
> our object to the level of C struct or Pascal-style record-type. To
> take away the state, and only be left with behavior, would basically
> leave a module/package or some pseudo-random collection of functions.
>
> So at this point, I think it is safe to say that an *object* should
> have both state and behavior.
>
> Now, back down from the theoretical cloud to reality. I would like to
> show some canonical class-method examples (and in some cases, show
> how they are broken), then show how they might be better accomplished
> in Perl 6 without the need for class methods to be inherited.
>
> == Instance Counting Class
>
> The most common example given for class methods is an "instance
> counter". Here is how one might (naively) look in Perl 6:
>
> class A {
>      our $.count;
>      method count (Class $c:) { $.count; }
>      submethod BUILD {
>          $.count++;
>      }
> }
>
> Each time an instance of A is created the counter is incremented. So
> that ...
>
> A.count; # 0
> A.new;
> A.count; # 1
>
> Now this makes sense, until we subclass A.
>
> class B is A {}
>
> A.count; # still 1
> B.new; # calls A::BUILD
>
> A.count; # 2
> B.count; # 2
>
> Clearly, we only have one instance of A, and one instance of B, so
> those numbers are wrong. It could be argued that since B is a subtype
> of A, we do have two A's, but the argument does not work in reverse.
> But either way, I would argue that the results shown above are
> misleading, and probably not what the programmer intended.

We definitely have two instances of A since, B.isa(::A). We also have
a fragile implementation of count.

  class A {
    our %.count_of

    method count (Class $c:) { %.count_of{$c} }

    method BUILD {
      $class = ($?SELF.class)

      @countable_ancestors = $class.ancestors.uniq.grep :{.isa(::A)}

      for $class, [EMAIL PROTECTED] -> $c { %.count_of{$c}++ }
    }

Where we're assuming I've got the syntax of 'for' right, and that
'ancestors' is a class method that returns all of a class's
ancestors. This might not work too well in the face of a dynamic
inheritance tree, but it should be possible to work around. Something
like this might work:

   Class A {
     our %.instance_count_of

     method count (Class $c: ?$with_descendents = undef) {
       my @interesting_classes = $c;
       if $with_descendents {
         push @interesting_classes, *($c.all_subclasses);
       }
       [+] %.instance_count_of(@interesting_classes)
     }

     method BUILD {
       %.instance_count_of($?SELF.class)
     }
   }

Where we're assuming that a class can find all its subclasses 

-- 
Piers Cawley <[EMAIL PROTECTED]>
http://www.bofh.org.uk/

Reply via email to