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

I've just started taking a decent in-depth look at Catalyst with a view to using it in the next major project coming up at work. I like a lot of it, but one thing that really bugs me is the stash.

It's basically a global variable, even though it's being passed round in the Catalyst::Context object. I don't have a problem with that, globals can be useful sometimes. But what concerns me is the way it's used to communicate between functions. eg.
sub foo : Local { my ($self, $c) = @_; $c->stash->{foo} = 'store some stuff'; $self->forward('bar'); } sub bar : Private { my ($self, $c) = @_; # ... do something with data put in stash by foo() }
Of course, you don't *have* to do it that way, especially since forward() now supports passing of arguments. But a lot of the Catalyst::* modules do things like (from Catalyst::View::HTML::Template for use with HTML::Template):
$template->param( base => $c->req->base, name => $c->config->{name}, %{ $c->stash } );
It seems most of the other view modules take this sort of a approach as well.

So you're just expected to put some things into the stash, forward to the view, and automagically your template gets populated with everything currently in the stash (whether you need or want it).

Again, you don't *have* to do it that way, you can easily create your own HTML::Template view module that passes parameters to the process() function, but it seems like the 'default' way of doing things is encouraging the use of stash.

What happens if another module decides to overwrite a whole lot of stash variables that you were using? True, there has to be sloppy coding along the line somewhere, but why make it easier for this sort of problem when you could just as easily protect against this sort of thing by passing parameters around?

I'm looking forward to using Catalyst in future applications, but these issues are making me slightly uneasy. I'd like someone to put my mind at rest :)

Replies are listed 'Best First'.
Re: Catalyst and the stash
by agrundma (Novice) on Jul 19, 2005 at 19:31 UTC
    Actually, the real purpose of the stash is to serve as a place to put data that will be read by the view (templates). It is not designed to be used as a data-passing mechanism between functions, but was used that way in some places because of the original lack of parameter support in forward(). Now that you can pass params in forward, there should be no reason to use the stash for temporary data passing. All view classes should be using the stash to populate themselves with data.
Re: Catalyst and the stash
by phaylon (Curate) on Jul 19, 2005 at 18:53 UTC
    Well, it's Perl, so there's more freedom but also more responsibility ;) Also, you can overwrite (for example) the "process" method of the template, get the template out of the arguments, and set the stash variable.

    Personally, I never had any problem using the stash or organizing the passed data. More the other way, it gives great possibilities. Also, if modules write into the stash or use it, it's usually documented.

    What I also like on Catalyst, if there's no other way than to look in the code, it's well written and easy to understand. My impression in #catalyst is also, that patches and ideas are very welcome, just to say.


    Ordinary morality is for ordinary people. -- Aleister Crowley
      Well, it's Perl, so there's more freedom but also more responsibility
      Yep, I agree, I have no problem with the freedom being available, only with it being used irresponsibly.

      I guess this whole issue might just be due to the fact that forward() didn't support passing of parameters. Now that it does, maybe a lot of the support modules will be enhanced to take advantage of this.
Re: Catalyst and the stash
by perrin (Chancellor) on Jul 19, 2005 at 19:41 UTC
    I had similar concerns about the way many plugins add methods to the context ($c) namespace. So far though, it seems to have worked to just let the community police that itself. It's something to keep in mind though, if you are thinking of writing your own private plugins that add to $c but are not known about by other authors who might stomp on your namespace.
Re: Catalyst and the stash
by revdiablo (Prior) on Jul 19, 2005 at 18:53 UTC

    I have not used Catalyst, but its stash sounds much like POE's heap, so my experience with POE might be useful here. I use the heap for things that I will need later. Later might mean the next state, or it might mean 15 states after this one. Obviously, in the face of this type of uncertainty, argument passing isn't going to work. On the other hand, when I want to pass arguments to states, I pass arguments.

    I suggest you approach Catalyst the same way. Use the stash for long term storage, and argument passing for, well, argument passing. If some modules use the stash as an argument passing mechanism, that's unfortunate. I wouldn't base my decision whether to use it on that alone, though. Just do things the way you feel comfortable.

    Update: as per jest's reply, my analogy is obviously flawed. Kindly ignore my post. :-)

      I do want to point out that the stash should _not_ be used for long-term storage; if you need this, use a session. The stash is cleared at the end of every request.
Re: Catalyst and the stash
by astroboy (Chaplain) on Jul 19, 2005 at 19:55 UTC
    This doen't seem any different from the param method in CGI::Application - sometimes you need to have data globally accessible to your code. It does act like a global, but so do session variables ... they suffer the same risks as well, but they sure are useful. If you're worried about naming collissions, you could include your namespace in your stash:
    $c->stash->{MyAppFoo} = 'store some stuff';
      It's pretty rare to send your entire CGI::App param() hash to a template though!

      CGI::App's param() is meant to allow instance scripts to configure the application via the PARAM option to new(). Using it to hold global data generated inside the app isn't a very good idea in my opinion.


        CGI::App's param() is meant to allow instance scripts to configure the application via the PARAM option to new().

        True, but I don't think that it's the only reason for param(). Param was recently a hot topic on the CGI::App mail list. It's also the preferred way for creating your own variables in your subclass of CGI::App without adding to the internal blessed hash directly. As such, you don't always want to do this in new(). It seems to me that the Catalyst stash is performing the same task.

Re: Catalyst and the stash
by monsieur_champs (Curate) on Jul 20, 2005 at 12:47 UTC

    Seems to me that this is easy to solve.

    Please note that by using this, you can avoid rubishness trought being not lazy, and get all control your need over your view modules income data, without hurting the freedom of others. I would think twice before using such a thing. ;-)