Catalystic conversion - part 3

autarch on 2007-03-02T01:49:45

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.


Traits

Ovid on 2007-03-02T10:51:18

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.

Re:Traits

sigzero on 2007-03-02T12:47:27

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

Okay, go ahead. : )

Documentation...

phaylon on 2007-03-02T16:34:06

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?

Re:Documentation...

autarch on 2007-03-02T17:44:40

Right here.

BTW, I'm on the Catalyst list if you want to move this discussion there.

Re:Documentation...

phaylon on 2007-03-03T23:46:39

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.