Open scmorrison opened 6 years ago
I'd not expect this to work. Dynamic variables must be in dynamic scope to be visible. The route
block is run right at the point it is encountered, in order to build the router transform that's stored in $application
. Thus it is out of dynamic scope by the time any of the handlers are run. Further to that, Cro runs handlers on the thread pool (not directly, but as a result of using Supply-based concurrency), and each thread is its own dynamic scope.
I'm guessing this is golfed from a more practical problem; what were you originally trying to achieve?
I'm not the OP, but I've tried to do stuff like this.
In the past, I've used Mojolicious which has concepts like the stash and helpers that are good for maintaining not quite global variables that are visible throughout the application and routes.
What is the best way to handle those sort of variables?
@jnthn, thanks for the explanation. This was just something I stumbled on. I was experimenting with dynamic variables and trying to see if they were accessible across nested modules when importing from separate .pm6 files. I threw a route {}
block in one of the nested modules and lost access to the dynamic variable.
To illustrate your point about how the dynamic variable is not carried across threads / each thread has its own dynamic scope:
my $*dyn = 'I am dynamic';
Thread.start({
try {
say $*dyn; # Dynamic variable $*dyn not found
CATCH { default { say .Str } }
}
});
@CurtTilmes State is something we have to be really quite careful about, given that requests may be processed concurrently in the thread pool - and with HTTP/2.0 that applies even to requests on a single connection. That said, I don't think the state being dealt with by the Mojo stash really is "global-ish" in nature, but really scoped to the lifetime of a particular request - and we can rely on that being manipulated by one thing at a time.
I guess the most immediate application for attaching Extra Stuff to requests is middleware being able to pass extra data onward. That can already be done relatively easily using a Perl 6 built-in feature: mixins.
role RequestDataObject {
has $.data-object;
}
...
$request does RequestDataObject($the-data)
Which is not quite as lightweight as having a hash to poke things into, but has its attractions: the lifetime is clearly that of the request, one can smartmatch to see if the extra state is there, typo'ing the property name gives a missing method error with typo suggestions, more refactoring potential, etc.
About helpers (I think that's my least favorite name in programming for anything... :-)), that looks like a way to be able to write things that one can call in request/response processing logic and have access to the request or response. If that's all they are, then I suggest:
use Cro::HTTP::Router
and then write the "helpers" in subs that use request
and/or response
(these are resolved using dynamic variables, so it doesn't matter the code using them isn't in the lexical scope of the request handler itself). In fact, one can use things like header
, not-found
and all the rest in such "helpers" too, since they work in terms of dynamic request
and response
.is export
use
them (can even take advantage of lexical import to just use
them inside a particular route
block).I don't think there's any need for an object-y approach here; let functions be functions.
In general, I'm open to adding things to Cro as needed, but if we can discover elegant solutions that take advantage of Perl 6's numerous built-in features without feeling boilerplate-y, then to me that's preferable.
Dynamic variables get lost inside of route HTTP method (get, post, etc.) routines: