Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • I'm waiting to see what shakes out of A12 before I do much more work on it. Very few people really understand the point of roles; I hope that Larry will explain it far better than I've been able to do.

    • by Ovid (2709) on 2004.02.14 21:36 (#28463) Homepage Journal

      I don't blame you. It looks like there's a lot of potential there, but how it integrates into Perl 6 will be interesting.

      I just finished an alpha version of Class::Trait and I'm writing the docs now. I don't have a tarball uploaded, but the interface looks like this (borrowing heavily from your examples):

      package Person;
      # make them a lifeguard, but ensure that they use &Trait::Dog::swim and not
      # &Trait::LifeGuard::swim
      use Class::Trait 'Trait::LifeGuard';
      use Class::Trait 'Trait::Dog' => { explicit => 'swim' };

      # the dog will want a &doggie_treat, but since it's AUTOLOADed or inherited,
      # we must explicitly promise that it will be available
      Class::Trait->promise('doggie_treat');
      Class::Trait->assemble;

      1;

      package Trait::LifeGuard;

      sub swim {
        return Trait::LifeGuard::_swim();
      }

      sub save_drowning_swimmer {
        my (undef, $swimmer) = @_;
        # save the swimmer
      }

      1;

      package Trait::Dog;

      Class::Trait->expects('doggie_treat');

      sub swim {
        my ($class, $target) = @_;
        Trait::Dog::_eat($class->doggie_treat);
        # swim to $target
      }

      sub _eat {
        ...
      }

      1;

      Essentially, it boils down to traits having expectations and the primary class making promises. If the primary class does not have a given method in its symbol table (due to AUTOLOAD or inheritance), then it promises that the method will be available when called (Class::Trait->promise('doggie_treat');). A trait is expected to not make promises at the current time (that may change).

      A trait might need methods it doesn't provide, though, so it sets expectations

      package Trait::Dog;
      Class::Trait->expects('doggie_treat');

      As the primary class and traits are used, a tally of all promises, expectations, and actual methods is made. When the Class::Trait->assemble method is called, the interface is validated and flattened into the primary class.

      To resolve conflicts, you must explicitly request a given method from a trait.

      use Class::Trait 'Trait::Dog' => { explicit => 'swim' };

      All methods in a package that do not begin with an underscore (or the "import" method) are added to the list of traits to be flattened. If a trait wants a private helper method, it must call it via the fully qualified name (or a private subref).

      So far, the tests pass, but it does have a few limitations. I worked hard to make the interface as self-explanatory as possible. If you or anyone else is interested, I can provide a download link for the tarball when it's ready.