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

use Perl Log In

Log In

[ Create a new account ]

autarch (914)

autarch
  (email not shown publicly)
http://www.vegguide.org/

Journal of autarch (914)

Thursday March 01, 2007
08:49 PM

Catalystic conversion - part 3

[ #32541 ]

Some more problems:

Issue #2 - Request (and Response) subclassing

This is a problem we encountered in Mason development as well, and I don't know of any great solutions.

The basic issue is that everyone wants a piece of the request (and response) class. It's the logical place to put app-specific per-request/response attributes & behavior. I note that the Catalyst docs seem to encourage you to do this:

{
    package Catalyst::Request;
    __PACKAGE__->mk_accessors('toejam');
 
    sub foo { }
}

Naughty, naughty. This works fine for one app, but under mod_perl you might have a bunch (or a few) Catalyst apps sharing one interpreter, and the above is massively polluting.

The next solution you think of is subclassing a request. That works fine when you're writing an application. You subclass Catalyst::Request, let's call it VegGuide::Request, and add your new bits there.

This fails miserably if you want to distribute stuff on CPAN, however. A good example is Catalyst::Action::REST, which comes with its own request subclass. But what if there were also a Catalyst::Request::WhizBang that I wanted to use? I guess I could multiply-inherit in VegGuide::Request, but that gets really gross.

Another alternative is to encourage CPAN authors to distribute request/response class changes/improvements in the form of trait classes. Then in your app you can do this:

package VegGuide::Request;
 
use base 'Catalyst::Request';
 
use Class::Trait ( 'Catalyst::RequestTrait::REST' );
use Class::Trait ( 'Catalyst::RequestTrait::WhizBang' );

I guess that's no so different from multiple inheritance, really, but it feels saner, especially when those Catalyst::RequestTrait classes probably provide one or two attributes or methods each.

We came up with an entirely different solution in Mason, but this was before Class::Trait, and nowadays I'd probably go the trait route. For the curious, the Mason solution involves a method called alter_superclass(), and is well, really bizarre.

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 haven't touched Catalyst in a long time, but when I did, I seem to recall that they implemented plugins via multiple inheritance. I urged them to consider something different, including a trait model. It would have been far more sane, but they were concerned (if I recall correctly) about backwards compatibility. Traits solve so many problems and I wish more people would take a look at them. Of course, it would help if I completely rewrote the Class::Trait documentation.

    • Of course, it would help if I completely rewrote the Class::Trait documentation.

      Okay, go ahead. : )
  • The basic issue is that everyone wants a piece of the request (and response) class. It's the logical place to put app-specific per-request/response attributes & behavior. I note that the Catalyst docs seem to encourage you to do this:

    Where does the documentation say that?

    --
    Ordinary morality is for ordinary people. -- Aleister Crowley
    • Right here [cpan.org].

      BTW, I'm on the Catalyst list if you want to move this discussion there.
      • Argh. That was even _my_ fault. I hadn't done that much with Catalyst, and this document is really outdated. Fortunately, I'm about to finish a new version that focuses more on best practices.
        --
        Ordinary morality is for ordinary people. -- Aleister Crowley