Front page | perl.perl5.porters |
Postings from July 2009
Re: %^H (was Re: Coring Variable::Magic / autodie fights with string eval in Perl 5.10.x)
Thread Previous
|
Thread Next
From:
Rafael Garcia-Suarez
Date:
July 7, 2009 09:19
Subject:
Re: %^H (was Re: Coring Variable::Magic / autodie fights with string eval in Perl 5.10.x)
Message ID:
b77c1dce0907070919m6d771fc7p9aa6dc24870dccf@mail.gmail.com
2009/7/7 Abigail <abigail@abigail.be>:
>> 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).
There are many features that would be nice for Perl 5 in that list.
But nothing to install a special block in the caller at compile-time.
> 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.
>
--
"You don't mean odds and ends, you mean des curieux et des bouts",
corrected the manager.
-- Terry Pratchett, Hogfather
Thread Previous
|
Thread Next