Re: Magic blocks (was: Compile-time undefined sub detection)
- Original Message - From: Larry Wall [EMAIL PROTECTED] To: [EMAIL PROTECTED] Sent: Saturday, March 06, 2004 10:39 PM Subject: Re: Magic blocks (was: Compile-time undefined sub detection) Oh, I accidentally left NEXT out of my canonical list. We do need to have the equivalent to Perl 5's continue. Will there be a corresponding 'will next' property on variables? If so, then this could be a very nice way to solve the problem of how to access the 'prior' element in a for loop: for @array - $current { state $prior will next {$prior := $current} will leave {$prior := undef}; ... } $prior is a state variable so that it retains its value between iterations of the loop. The 'will next' property binds $prior to $current just before the loop binds $current to the next element of @array; the result is that in every iteration of the loop after the first $prior is bound to the same element of @array that $current was bound to in the previous iteration. The 'will leave' property ensures that we don't keep a reference to an element of @array after we leave the loop; it also ensures that $prior has the correct value of undef() when we start the loop the next time. Joe Gottman
Re: Magic blocks (was: Compile-time undefined sub detection)
On Sat, Mar 06, 2004 at 06:39:44PM -0800, Larry Wall wrote: my @x will begin {...} # at BEGIN time my @x will check {...} # at CHECK time (redefined to unit check) my @x will init {...} # at INIT time my @x will end {...}# at END time Sorry, perhaps I wasn't paying close enough attention, but suddenly we've leaped from oddly named subs that get called at interesting times, to array variables with oddly-named properties (or attributes, or whatever). Je ne comprend pas :-(. Dave. -- A walk of a thousand miles begins with a single step... then continues for another 1,999,999 or so.
Re: Magic blocks (was: Compile-time undefined sub detection)
On Mon, Mar 08, 2004 at 11:57:04PM +, Dave Mitchell wrote: : On Sat, Mar 06, 2004 at 06:39:44PM -0800, Larry Wall wrote: : my @x will begin {...} # at BEGIN time : my @x will check {...} # at CHECK time (redefined to unit check) : my @x will init {...} # at INIT time : my @x will end {...}# at END time : : Sorry, perhaps I wasn't paying close enough attention, but suddenly we've : leaped from oddly named subs that get called at interesting times, to : array variables with oddly-named properties (or attributes, or whatever). : Je ne comprend pas :-(. Oddly named subs are cool as such, but there are times when you don't so much want an oddly named sub as an oddly named method. These are just oddly named methods on the container in question (which certainly doesn't have to be an array). Underneath they're still oddly named subs in terms of when they run. But they implicitly get (as their first argument/invocant/topic) the container in question, so they can do fancy things with $_ and .foo and Cwhen and such. The will first syntax is mentioned in A6. Plus we discussed it last April with respect to state variables--see message below. Larry From [EMAIL PROTECTED] Tue Apr 15 11:56:23 2003 Date: Tue, 15 Apr 2003 11:19:42 -0700 From: Larry Wall [EMAIL PROTECTED] Subject: Re: Initializations outside of control flow To: [EMAIL PROTECTED] On Tue, Apr 15, 2003 at 10:34:35AM -0400, Mark J. Reed wrote: : It just seems like there should be a way to accomplish that without : the visual clutter. Perhaps a trait: : : my $count is initially($INITIAL_VALUE); : : If there's already a defined way of doing that in Perl 6, please : point me at it and I'll go away chastened but happy. Otherwise, : does this seem a reasonable approach? Ideas for a better name for : the trait? The traits in question are already named corresponding to the various initialization closures, which at the moment are named BEGIN {...} CHECK {...} INIT {...} FIRST {...} ENTER {...} so, since the variable in question is the topic of the closure, we have my $count will begin { .set($INITIAL_VALUE) } my $count will check { .set($INITIAL_VALUE) } my $count will init { .set($INITIAL_VALUE) } my $count will first { .set($INITIAL_VALUE) } my $count will enter { .set($INITIAL_VALUE) } Perhaps those particular traits are smart enough to distinguish whether they have a closure or not, and build an appropriate closure if not, so we could also have my $count is begin($INITIAL_VALUE) my $count is check($INITIAL_VALUE) my $count is init($INITIAL_VALUE) my $count is first($INITIAL_VALUE) my $count is enter($INITIAL_VALUE) At the moment, I believe that = always happens at run-time. So my $count = BEGIN { calculation() } would do the calculation at compile time but assign the resulting value every time the statement is executed. This means that a declaration like: state $where = $x; is almost certainly incorrect. It should probably be one of state $where is begin($x); state $where is check($x); state $where is init($x); state $where is first($x); Could go so far as to lose the is, treating these as variants of is. state $where begin($x); state $where check($x); state $where init($x); state $where first($x); The other possible approach would be to allow blockless closures like BEGIN (state $where = $x); CHECK (state $where = $x); INIT (state $where = $x); FIRST (state $where = $x); Maybe the parens aren't necessary, if they just introduce a syntactic statement: BEGIN state $where = $x; CHECK state $where = $x; INIT state $where = $x; FIRST state $where = $x; But I think it would be a mistake to have = running at random times depending on either the foo and BAR in foo $x = BAR { ... } Larry
Magic blocks (was: Compile-time undefined sub detection)
Okay you guys, you're running away from one kind of madness and proposing various other kinds of madness in its place. Mostly you're confusing what should be easy and what should be possible. First a note about cleanup dependencies. In general, these should be driven by the structure of the data, not the structure of the program. If you want to make sure one piece of data is cleaned up before another, make sure there's a reference that enforces that. That's the principle on cleanup. It's also, more or less, the principle on initialization. What these various blocks are obscuring from your calculations is that there is a data structure for each of these sets of queued events, and as long as there's a way to name such a queue, it's not necessary to access it through the official block name. It would be nice if the property that stores a particular queue has a related name, of course. But for fancy things, we don't have to add options to the syntax of blocks in order to manipulate these queues. If you want to make sure you're last in the END queue, just manipulate that queue. We also don't need a new abstraction like execution group, unless by that you simply mean one of these callback queues. We particularly don't need to orthogonalize all the names and make them equally obfuscational. This is very much a place where easy things should be easy, and hard things should be difficult. So here's the ruling. We don't need any special names for hacking on the queue in another module. So CHECK means UNITCHECK, always. There's no MAINCHECK name. If you want to do something fancy to the main program's CHECK list or END list, then at export time, modify the queue contained in Main's CHECKLIST property or ENDLIST property. If you really, really, really, want something to run last, then install something into Main::ENDLIST that looks to see whether there's anything after it when it gets triggered, and if so, reinstalls itself at the end again. And then we can have the entertaining situation of two or more modules both playing leapfrog trying to be last. Perhaps something fancy with priorities can be worked out, but if so, that's the domain of direct queue manipulation routines. It has nothing to do with the easy-to-use block declarations, which have to remain simple interfaces, or there's no point to them. So we're back to the standard four phase oriented blocks: my @x will begin {...} # at BEGIN time my @x will check {...} # at CHECK time (redefined to unit check) my @x will init {...} # at INIT time my @x will end {...}# at END time plus these four block oriented blocks: my @x will pre {...}# at PRE time (return boolean for DBC) my @x will enter {...} # at ENTER time (block entry) my @x will leave {...} # at LEAVE time (block exit) my @x will post {...} # at POST time (return boolean for DBC) plus three specialty times for things with lifetimes not related to blocks: state @x will first {...} # at FIRST time (first time through) has @.x will build {...}# at BUILD time (object init time) has @.x will destroy {...} # at DESTROY time (object final time) There's no LAST corresponding to FIRST because you can't generally tell when you've called a block for the very last time. (If there is a LAST, it'd be loop related, but then FIRST and LAST aren't really opposites, and it'd duplicate LEAVE anyway.) Oh, and I guess we still have the two leave variants: my @x will keep {...} # at LEAVE time, if leaving successfully my @x will undo {...} # at LEAVE time, if leaving unsuccessfully There's also, in a sense, a catch time, but you can't have more than one of those, so there's no CATCHLIST property to modify. If you're trying to add semantics to your CATCH, you're probably wanting an undo instead. A good case can be made for all of those--unless you happen to be against transactional programming, or design by contract. Or state variables, or objects, or blocks, or modules... :-) Larry
Re: Magic blocks (was: Compile-time undefined sub detection)
Oh, I accidentally left NEXT out of my canonical list. We do need to have the equivalent to Perl 5's continue. Larry