jcupp has asked for the wisdom of the Perl Monks concerning the following question:

MOnKs--there seem to be lots of ways to implement a Mixin pattern. I've tried:

1) using Exporter: seems real clean with tags 2) *sub1 = \&OtherMod::sub1 for all mixins 3) subclassing and re-blessing the reference

Basically, I want to turn groups of methods on/off, but share the same data in the blessed reference, what else is there?

Replies are listed 'Best First'.
Re: Best way to do Mixin Class
by ariels (Curate) on Apr 06, 2002 at 11:46 UTC

    Do what you would in C++: multiple inheritance (into a subclass). A mixin class is really just a class providing behaviour. It lets you add particular methods to an existing class, without messing about with that class.

    An example should make things clear...

    Say we have (unrelated) classes Foo and Bar, each with a method val with similar semantics:
    package Foo; sub new { my ($class) = @_; return bless [], $class; } sub val { my $self = shift; $self->[0] = $_[0] if @_; "Foo($self->[0])"; } package Bar; sub new { my ($class) = @_; return bless { val => 'nothing' }, $class; } sub val { my $self = shift; $self->{val} = $_[0] if @_; "Bar($self->{val})"; }
    We'd like to have a method that prints the val, but we don't want to touch our 2 classes (maybe they're not our responsibility, or maybe we also need them unadorned, or whatever... that's why we want a mixin!). Here's the mixin:
    # Something to mixin package Printer; sub print { my $self = shift; my $val = $self->val; print "Value is $val\n"; }
    If we manage to get a Foo or a Bar to execute Printer::print, we get our desired behaviour.

    Multiple inheritance to the rescue! Define Foos that are also Printers...

    package Foo2; use vars '@ISA'; @ISA = qw(Foo Printer); package Bar2; use vars '@ISA'; @ISA = qw(Bar Printer);
    Use them as you'd expect:
    package main; my $x = new Foo2; my $y = new Bar2; $x->val(17); $y->val('xyzzy'); $x->print; $y->print;

    Hope this helps...

      Is it a good idea/possible to modify @ISA at run-time? I guess as long as you don't "use base ..."

        It's the traditional way (sorry, at least my 5.004 roots are showing). What I do is well-documented, e.g. in perlboot or perltoot.

        As long as you don't change @ISA while doing important stuff, it should be OK. But note the warning about changing @ISA in perlobj!

        In any case, using base can't be bad for you...

Re: Best way to do Mixin Class
by jcupp (Acolyte) on Apr 06, 2002 at 03:11 UTC
    Oh, and 4) AUTOLOAD - dispatch style...

    All of this based on a start-up state. Would this be some kind of wacky state/dispatch/mixin monster??

Re: Best way to do Mixin Class
by dws (Chancellor) on Apr 07, 2002 at 00:02 UTC
    there seem to be lots of ways to implement a Mixin pattern. ... Basically, I want to turn groups of methods on/off, but share the same data in the blessed reference

    You are using "mixin" in a way I'm not familiar with. The term originally predated languages that supported interfaces (like Java), and meant to "mix in" methods from one class hierarchy into another so that two objects could be used interchangeably in a particular context (i.e., to fake an interface, without the benefit of multiple inheritance). Perhaps the meaning has changed. Do you have a reference you could point me toward to describe the "mixin pattern"?

      ...because I'm using the wrong words. Whatever it's called, I need to allow/disallow (turn on/off) methods based on a "role" property of the class, for example: a publisher vs. browser vs. admin role for editing, viewing, and everything for a database API. I think I'll just modify @ISA run-time, that seems to be the easiest answer.