Since the list has been quiet for the last little while, I thought I
would stir things up a bit.  There was a thread about Class::Trait
recently on perlmonks that caught my attention:

http://perlmonks.org/?node_id=509958

I had looked at Traits before, but never found the time to look into
them carefully.  The reason I think they are interesting, is that
Traits aim to solve a lot of the problems with both Multiple
Inheritance and Mixins.  And since the plugin system in
CGI::Application is based around a mixin architecture, I think it is
worth a look.

In CGI::Application, we don't really have a plugin interface.  We have
conventions and best practices that tell developers to just use
Exporter to export methods into the caller class (ie a very simple
mixin strategy).

But mixins have some problems and dangers associated with them.  The
biggest one being method name colisions.  What happens if a plugin
tries to export a method that already exists in the caller class?  It
probably clobers it in most instances, depending on how the plugin
author implemented their code.

Traits are not really much more than mixins with a lot of extra checks
and balances for namespace collisions, and ways to overcome those
problems when they arise.  First of all, a Trait will never overwrite
an existing method in the caller.  What it will do is allow you to
alias the trait method with a new name, so that you can still use the
method provided by the trait without it conflicting with your existing
code.

For example lets take the LogDispatch plugin.  It exports a 'log'
method into the caller namespace.  Lets say you already have a 'log'
method in there that you do not want to get rid of.  When you load the
LogDispatch Trait, you can tell it that you want the 'log' method, but
you want to call it 'get_logger' instead.  Class::Trait will
automatically export a 'get_logger' method that is aliased to the
original 'log' method in the Trait.


Another nice benefit of Traits is that you can specify method
requirements in a Trait.  So if I implemented the Session plugin using
traits, and I put in a requirement that the Session trait requires a
'dbh' method to be available, then the Class:Trait module would make
sure that a 'dbh' is available and provide an error if it can not find
a dbh method (either in the caller class, or in another Trait that is
also being loaded).


Class::Trait will add a slight bit of extra processing to the module
at startup, since it is doing more work than a straight Exporter style
mixin, but all of this work is done at compile time.  All of the
exported methods are still flattened into the caller's namespace, so
there is absolutely no extra runtime penalty.

Loading plugins will also look slightly different, since they are
loaded through the Class::Trait module instead of being 'use'd
directly:

use Class::Trait qw(CGI::Application::Plugin::Session);

We could create a simple wrapper that simplifies that to something like this:

use CGI::Application::Plugin qw(Session);

- or with some extra options -

use CGI::Application::Plugin
        'LogDispatch' => {
            alias => { log => 'get_logger' },
        },
        'Session'
);


I think it might be useful at some point in the future to look at
using Traits instead of straight exporter style mixins to implement
the plugin system we use today.  It would add extra safeguards and
checks into the plugin system that would make it more robust, and it
adds a clean conflict resolution mechanism in case of method name
conflicts.

Cheers,

Cees

---------------------------------------------------------------------
Web Archive:  http://www.mail-archive.com/[email protected]/
              http://marc.theaimsgroup.com/?l=cgiapp&r=1&w=2
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to