Front page | perl.perl5.porters |
Postings from July 2009
Re: %^H (was Re: Coring Variable::Magic / autodie fights withstring eval in Perl 5.10.x)
Thread Previous
|
Thread Next
From:
Abigail
Date:
July 7, 2009 08:58
Subject:
Re: %^H (was Re: Coring Variable::Magic / autodie fights withstring eval in Perl 5.10.x)
Message ID:
20090707155839.GA18803@almanda
On Tue, Jul 07, 2009 at 05:46:46PM +0200, Rafael Garcia-Suarez wrote:
> 2009/7/7 Nicholas Clark <nick@ccl4.org>:
> > No, I don't have any real idea of Perl-space syntax for an end of scope
> > hook. Or how to meaningfully encode a "restart of scope" hook, which a
> > string eval would need. [After all, a pragma is in force for the compilation
> > of the string eval, and on completing the compilation of that string eval,
> > it goes out of scope, doesn't it? :-)]
>
> How does P6 do it ? Isn't there a special block à la BEGIN/END/CHECK etc ?
> (B::Hooks::EndOfScope uses a special block syntax)
Yes, it's LEAVE (any block exit), KEEP (succesful exit), UNDO (unsuccesful).
Quoting from http://svn.pugscode.org/pugs/docs/Perl6/Spec/S04-control.pod
=head1 Closure traits
A C<CATCH> block is just a trait of the closure containing it. Other
blocks can be installed as traits as well. These other blocks are
called at various times, and some of them respond to various control
exceptions and exit values:
BEGIN {...}* at compile time, ASAP, only ever runs once
CHECK {...}* at compile time, ALAP, only ever runs once
INIT {...}* at run time, ASAP, only ever runs once
END {...} at run time, ALAP, only ever runs once
START {...}* on first ever execution, once per closure clone
ENTER {...}* at every block entry time, repeats on loop blocks.
LEAVE {...} at every block exit time
KEEP {...} at every successful block exit, part of LEAVE queue
UNDO {...} at every unsuccessful block exit, part of LEAVE queue
FIRST {...}* at loop initialization time, before any ENTER
NEXT {...} at loop continuation time, before any LEAVE
LAST {...} at loop termination time, after any LEAVE
PRE {...} assert precondition at every block entry, before ENTER
POST {...} assert postcondition at every block exit, after LEAVE
CATCH {...} catch exceptions, before LEAVE
CONTROL {...} catch control exceptions, before LEAVE
Those marked with a C<*> can also be used within an expression:
my $compiletime = BEGIN { localtime };
our $temphandle = START { maketemp() };
As with other statement prefixes, these value-producing constructs
may be placed in front of either a block or a statement:
my $compiletime = BEGIN localtime;
our $temphandle = START maketemp();
This can be particularly useful to expose a lexically scoped
declaration to the surrounding context. Hence these declare the same
variables with the same scope as the preceding example, but run the
statements as a whole at the indicated time:
BEGIN my $compiletime = localtime;
START our $temphandle = maketemp();
(Note, however, that the value of a variable calculated at compile
time may not persist under run-time cloning of any surrounding closure.)
Code that is generated at run time can still fire off C<CHECK>
and C<INIT> blocks, though of course those blocks can't do things that
would require travel back in time.
Some of these also have corresponding traits that can be set on variables.
These have the advantage of passing the variable in question into
the closure as its topic:
my $r will start { .set_random_seed() };
our $h will enter { .rememberit() } will undo { .forgetit() };
Apart from C<CATCH> and C<CONTROL>, which can only occur once, most
of these can occur multiple times within the block. So they aren't
really traits, exactly--they add themselves onto a list stored in the
actual trait (except for C<START>, which executes inline). So if you
examine the C<ENTER> trait of a block, you'll find that it's really
a list of closures rather than a single closure.
The semantics of C<INIT> and C<START> are not equivalent to each
other in the case of cloned closures. An C<INIT> only runs once for
all copies of a cloned closure. A C<START> runs separately for each
clone, so separate clones can keep separate state variables:
our $i = 0;
...
$func = { state $x will start { $x = $i++ }; dostuff($i) };
But C<state> automatically applies "start" semantics to any initializer,
so this also works:
$func = { state $x = $i++; dostuff($i) }
Each subsequent clone gets an initial state that is one higher than the
previous, and each clone maintains its own state of C<$x>, because that's
what C<state> variables do.
Even in the absence of closure cloning, C<INIT> runs before the
mainline code, while C<START> puts off the initialization till the
last possible moment, then runs exactly once, and caches its value
for all subsequent calls (assuming it wasn't called in void context,
in which case the C<START> is evaluated once only for its side effects).
In particular, this means that C<START> can make use of any parameters
passed in on the first call, whereas C<INIT> cannot.
All of these trait blocks can see any previously declared lexical
variables, even if those variables have not been elaborated yet when
the closure is invoked (in which case the variables evaluate to an
undefined value.)
Note: Apocalypse 4 confused the notions of C<PRE>/C<POST> with C<ENTER>/C<LEAVE>.
These are now separate notions. C<ENTER> and C<LEAVE> are used only for
their side effects. C<PRE> and C<POST> must return boolean values that are
evaluated according to the usual Design by Contract (DBC) rules. (Plus,
if you use C<ENTER>/C<LEAVE> in a class block, they only execute when the
class block is executed, but C<PRE>/C<POST> in a class block are evaluated
around every method in the class.) C<KEEP> and C<UNDO> are just variants
of C<LEAVE>, and for execution order are treated as part of the queue of
C<LEAVE> blocks.
C<FIRST>, C<NEXT>, and C<LAST> are meaningful only within the
lexical scope of a loop, and may occur only at the top level of such
a loop block. A C<NEXT> executes only if the end of the loop block is
reached normally, or an explicit C<next> is executed. In distinction
to C<LEAVE> blocks, a C<NEXT> block is not executed if the loop block
is exited via any exception other than the control exception thrown
by C<next>. In particular, a C<last> bypasses evaluation of C<NEXT>
blocks.
[Note: the name C<FIRST> used to be associated with C<state>
declarations. Now it is associated only with loops. See the C<START>
above for C<state> semantics.]
C<LEAVE> blocks are evaluated after C<CATCH> and C<CONTROL> blocks, including
the C<LEAVE> variants, C<KEEP> and C<UNDO>. C<POST> blocks are evaluated after
everything else, to guarantee that even C<LEAVE> blocks can't violate DBC.
Likewise C<PRE> blocks fire off before any C<ENTER> or C<FIRST> (though not
before C<BEGIN>, C<CHECK>, or C<INIT>, since those are done at compile or
process initialization time).
For blocks such as C<KEEP> and C<POST> that are run when exiting a
scope normally, the return value (if any) from that scope is available
as the current topic. (It is presented as a C<Capture> object.)
The topic of the outer block is still available as C<< OUTER::<$_> >>.
Whether the return value is modifiable may be a policy of the block
in question. In particular, the return value should not be modified
within a C<POST> block, but a C<LEAVE> block could be more liberal.
Thread Previous
|
Thread Next