Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

RFC: Scope::CHECK - Add CHECK blocks to the currently compiling lexical scope

by lodin (Hermit)
on Jan 04, 2008 at 06:52 UTC ( [id://660383]=perlmeditation: print w/replies, xml ) Need Help??

Perl 5.10 gives us UNITCHECK. So now we have CHECK that works at program level, UNITCHECK that narrows it down to a unit (e.g. a module/file). The next step is to narrow it down further to a lexical scope. That's what this module does.

A problem with UNITCHECK blocks as of today is that there's no way for a module to add a UNITCHECK to the unit that uses the module, making the use quite limited. Until there's a solution to that (if there will be), Scope::CHECK is an IMHO good enough alternative. Most modules are used at file scope, and modules that need to use this module shouldn't be dynamically loaded.

Here's a minimal demonstration of lexical CHECK blocks that pin-points where the block is executed:

use 5.010; use Scope::CHECK; { BEGIN { Scope::CHECK::->add(sub { say 'Checking scope' }) } BEGIN { say 'End of scope' } } BEGIN { say 'After scope' } __END__ End of scope Checking scope After scope

The complete .pm file is found below.

  • What do you think of the name?
    Scope:: already exists as a top-level name (Scope::Guard by chocolateboy), but there's also Hook::Scope by Artur Bergman. So guidelines from previous module are conflicting at best. If all goes well with this module I plan to also release Module::CHECK and Class::CHECK which are wrappers making it easier to use Scope::CHECK blocks for module and class authors. So I've adjusted the name according to those yet not released modules, as those fit the current CPAN scheme.
  • What do you think of the interface?
    I've considered making use Scope::CHECK sub { ... } equivalent with BEGIN { require Scope::CHECK; Scope::CHECK::->add(sub { ... }) } but I think it's a bit premature to do that now. The use statement may be useful for something else. Any ideas?
  • What do you think of the implementation?
    I've spotted two issues regarding threading (see the POD). Are there any other issues? Is it even safe to use %^H and DESTROY like that?
  • What do you think of the documentation?
    To sparse, too dense, too ... something? Anything missing?
  • Anything else?

Update: It looks as though I've found a way to stop blocks to run prematurely due to threads. (See the BUGS section in the POD for the issue.)

Update: The verdict from p5p is that this is explicitly not supported.

package Scope::CHECK; use 5.010; $VERSION = 0.001; use strict; { package Scope::CHECK::_OnScopeExit; sub new { bless $_[1], $_[0] } DESTROY { goto &{$_[0]} } } sub add { state @queue; state $Id = 0; shift; my ($code) = @_; push @queue, $code; $^H{__PACKAGE__ . '::_' . $Id++} = Scope::CHECK::_OnScopeExit::->new(sub { (pop @queue)->() }); } 1; __END__ =head1 NAME Scope::CHECK - Add CHECK blocks to the currently compiling lexical sco +pe =head1 SYNOPSIS use 5.010; use strict; use Scope::CHECK; { BEGIN { say '1. Compiling block.' } BEGIN { Scope::CHECK::->add(sub { say '4. Checking block, again.' +}); } BEGIN { Scope::CHECK::->add(sub { say '3. Checking block.' }); } BEGIN { say '2. Done compiling block.' } } BEGIN { say '5. Compiling rest of file.' } say '6. Running file.'; __END__ 1. Compiling block. 2. Done compiling block. 3. Checking block. 4. Checking block, again. 5. Compiling rest of file. 6. Running file. =head1 DESCRIPTION C<Scope::CHECK> lets you add C<CHECK> blocks to the currently compilin +g lexical scope. You probably want to do this because you need to def +er code until the whole scope is done compiling. C<Scope::CHECK> blocks run in LIFO order, just as C<CHECK> and C<UNITC +HECK> blocks. C<Scope::CHECK> blocks at "unit scope", i.e. the same lexical scope as + C<UNITCHECK> lives in, currently execute before C<UNITCHECK> blocks. + This depends on the inner working of perl, and this order isn't defi +ned anywhere as far as I know. =head1 METHODS =over =item Scope::CHECK->add(CODE) C<add> takes a subroutine reference as the only argument. The subrouti +ne will be executed when the currently compiling lexical scope is com +piled. =back =head1 BUGS =over =item Not really C<CHECK> blocks As the blocks aren't really C<CHECK> blocks but only pretend to be, th +ey might be executed too early before all compile passes are done. I +don't know before/during/after which compile pass they're executed. I +f you don't use C<Scope::CHECK> blocks to manipulate the optree you'r +e probably safe. Let me know if you have any problems related to this +. =item Threads C<Scope::CHECK> may not work in combination with threads. As long as y +ou don't B<start> any threads while a C<Scope::CHECK> block is waitin +g to execute or inside a C<Scope::CHECK> block you probably won't hav +e any problem. Here's an example of what can happen when you start a +thread before an active C<Scope::CHECK> block has been executed: use 5.010; use strict; use Scope::CHECK; use threads; { BEGIN { Scope::CHECK::->add(sub { say 'CHECK' }) } BEGIN { threads::->create(sub { say 'Thread started and ended. +' })->join } BEGIN { say 'Block compiled.' } } BEGIN { say 'Continuing compiling.' } __END__ Thread started and ended. CHECK Block compiled. CHECK Continuing compiling. Notice the extra CHECK in the output. The first is because the thread +ended, and the block was thus run prematurely. If you find any way to detect that a block executed because a thread e +nded, please let me know. =item When no scope is compiling If no scope is being compiled the block will be executed when the prog +ram exits, after C<END> blocks. This is not by design but due to curr +ent implementation. =back =head1 AUTHOR lodin =head1 COPYRIGHT Copyright 2008 lodin. All rights reserved. This library is free software; you can redistribute it and/or modify i +t under the same terms as Perl itself. =head1 SEE ALSO L<perlmod> for C<CHECK> and C<UNITCHECK>. =cut

lodin

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://660383]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-03-29 04:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found