End-of-scope actions: POST blocks.

2001-02-12 Thread Tony Olekshy

Nicholas Clark wrote:
 
 It makes them far more useful as tidy up things if they are tacked
 on at runtime, not compile time.

If I understand, it is proposed that code like this:

{
Alpha;
POST { Beta };
Gamma;
POST { Delta };
Epsilon;
}

will behave something like this:

{
my @onEnd = ();
try {
Alpha;
unshift @onEnd, sub { Beta };
Gamma;
unshift @onEnd, sub { Delta };
Epsilon;
}
finally {
foreach (@onEnd) { {$_}(); }
}
}

If so, then I have some observations.

  - It does have in-flow presence, so it doesn't suffer from the
problem that "always" has; POST is a statement, not a dangling
clause.  That fixes my main complaint with RFC 119.  On the
other hand, now there's nothing at the end of the scope to tell
you whether or not have to revisit the whole scope to check if
there are any POST clauses before you advance your mind to the
next statement.  Hmm.

  - It does solve the dual free problem.  Where RFC 88 says:

try { my $p = P-new; my $q = Q-new; ... }
finally { $p and $p-Done; }
finally { $q and $q-Done; }

the proposed method could say:

my $p = P-new; POST { $p-Done; };
my $q = Q-new; POST { $q-Done; };
...

On the other hand, there is no easy way to specify the order
in which $p-Done and $q-Done are invoked, independent of
the order in which $p and $q are constructed.  Hmm.

  - The semantics aren't quite the same as "try", which
declares exception handling blocks that are active once
try's block is entered, not when the declarations are
passed in the block.  Perhaps both mechanisms should be
supported?  RFC 88 does suggest that RFC 119 should be
considered independent of RFC 88, not as an alternative
thereto.

  - If the contents of a POST block raises an exception, how
does it affect other POST blocks?

In the example above, if $p-Done throws, then $q-Done should
be called, *and* vice versa, *and* unwinding should propagate if
either one threw (or anything else did for that matter, unless
it was caught without the catching throwing).

  - What about CATCH blocks (what RFC 88 calls "catch" and RFC 119
calls "except")?  What exactly is the interaction between these
dynamic POST and CATCH blocks?  We will need a detailed semantics,
along the lines of
http://www.avrasoft.com/perl6/rfc88.htm#Unwinding_Semantics

  - What about conditional CATCH blocks?  What syntax can we
use that interacts reasonably well with the rest of Perl?

  - What's the return value?  With RFC 88 you can say:

my $r = try { f() } catch { 0 };

What are the syntax and semantics in the CATCH/POST case?
Perhaps something like:

my $r = do { CATCH { 0 } f() };

Hmm.

Yours, c, Tony Olekshy



Re: End-of-scope actions: POST blocks.

2001-02-12 Thread James Mastros

On Mon, Feb 12, 2001 at 01:58:57PM -0700, Tony Olekshy wrote:
   - It does have in-flow presence, so it doesn't suffer from the
 problem that "always" has; POST is a statement, not a dangling
 clause.  That fixes my main complaint with RFC 119.  On the
 other hand, now there's nothing at the end of the scope to tell
 you whether or not have to revisit the whole scope to check if
 there are any POST clauses before you advance your mind to the
 next statement.  Hmm.
You seem to like a /lot/ of context markers for line-of-flow-control.  I
think that's somwhat misguided.  Perl already has a fair number of
out-of-line control semantics.  DESTROY, overloaded operators, and other
CAPITAL subs come to mind.  Moreover, I see no need to declare at the
beginning, middle, and end of a block that there's some exception
handling/out of order code going on.  If you want to understand a block of
code, reading everything textualy within the curley braces should be a
_minimum_, in which case, the word POST is plenty.

Also, I think that the syntax of exception processing should be minimial,
not only because I'll use it more if it's an extra 5 keystrokes instead of
an extra 15, but because the important things should stand out more --
that's why we support both leading and trailing ifs.

   - It does solve the dual free problem.  Where RFC 88 says:
 try { my $p = P-new; my $q = Q-new; ... }
 finally { $p and $p-Done; }
 finally { $q and $q-Done; }
 the proposed method could say:
 my $p = P-new; POST { $p-Done; };
 my $q = Q-new; POST { $q-Done; };
I like this MUCH better.  Even better (IMHO) would be:

my $p = P-new; POST: $p-Done;
my $q = Q-new; POST: $q-Done;

That only gets rid of one char (the ; after the -Done;s is already optional
as the last statement in a block), but it looks much less crowded to me.

I'd get rid of the caps on POST if I could, but that would be breaking
tradition for naming magical things.

 On the other hand, there is no easy way to specify the order
 in which $p-Done and $q-Done are invoked, independent of
 the order in which $p and $q are constructed.  Hmm.
You could always say:
my $p = new P;
my $q;
try {$q = new Q};
POST: $q-Done;
POST: $p-Done;

A little on the messy side, but workable.

   - The semantics aren't quite the same as "try"
TMTWTDI.

You could even have
{
  my $a = new A; POST: $a-Done;

  ...;
} catch { f() } finaly { g() };

(In which case, we go with order-encountered: first the POST, then the catch
(if approps), then the finaly.  (I don't think there should be a try keyword
neccessary at the top.  (Though if present, it should be a warning not to
have any danglers on the end of the block.))

   - If the contents of a POST block raises an exception, how
 does it affect other POST blocks?
I'd like to poist this rule:
Each POST block is independent.  If one raises an exception, it has no
effect on the others (including the value of @@).  This is equivlent to
saying that each POST block has an implicit eval {}.

If you want to do somthing if a POST {} block throws, use POSTs inside the
POST, or any of the other try {} catch {} finaly {} things.

 In the example above, if $p-Done throws, then $q-Done should
 be called, *and* vice versa, *and* unwinding should propagate if
 either one threw (or anything else did for that matter, unless
 it was caught without the catching throwing).
I don't follow you, neccessarly.  Is that what I just said?  I'm a little
bit behind in the jargon.

   - What about CATCH blocks (what RFC 88 calls "catch" and RFC 119
 calls "except")?  What exactly is the interaction between these
 dynamic POST and CATCH blocks?  We will need a detailed semantics,
 along the lines of
 http://www.avrasoft.com/perl6/rfc88.htm#Unwinding_Semantics
I'd go with a textual FIFO for danglers (what you have proposed, if I read
it correctly, then a LIFO on the in-body ones in order encountered.


BTW, when I say order encountered what I mean is that for this:

for (1, 2) {
POST {print "2\n"} if ($_ == 2);
POST {print "1\n"} if ($_ == 1);
print "$_\n";
}

Will output:
1
2
2
1

because we hit the 1 POST block in order-of-execution first, even though it
was second in textual order.

   - What about conditional CATCH blocks?  What syntax can we
 use that interacts reasonably well with the rest of Perl?
Hm?  POST { if (cond) { somthing } }.
CATCH is just shorthand.

   - What's the return value?  With RFC 88 you can say:
The return value is undef (or empty-list) until you hit a return statement.
If the code dies before returning, then it stays undef/() unless somthing
run after that (IE a CATCH/POST/catch/finaly/whathaveyou) returns.  (And if
it does, that blocks all execption processing.)

You can mess with the return arbitrarly if we support return-stack visiblity.

-=- James Mastros
-- 
"All I really want is somebody to curl up with and pretend 

Re: End-of-scope actions: POST blocks.

2001-02-12 Thread Tony Olekshy

James Mastros wrote:
 
 You seem to like a /lot/ of context markers for
 line-of-flow-control.  I think that's somwhat misguided.

I have not anywhere suggested that I'm against POST blocks; in fact
RFC 88 supports the similar "always" concept mentioned by RFC 119.
I'm just trying to figure out exactly how they should work.

 Moreover, I see no need to declare at the beginning, middle, and
 end of a block that there's some exception handling/out of order
 code going on.

Agreed.  I don't want to go overboard either.  I just want to extend
"eval" to become "try" (hey, saves you a character James), so it
can support the semantics of auxiliary catch and finally clauses,
while still leaving good-old eval alone.

 Also, I think that the syntax of exception processing should be
 minimial [...] because the important things should stand out
 more -- that's why we support both leading and trailing ifs.

Here I disagree.  I think indicating the presence of an exception
handling scope should be made to stand out quite a lot, because I do
think it's quite important.  It's, well, exceptional.

- It does solve the dual free problem.  Where RFC 88 says:
 
  try { my $p = P-new; my $q = Q-new; ... }
  finally { $p and $p-Done; }
  finally { $q and $q-Done; }
 
  the proposed method could say:
 
  my $p = P-new; POST { $p-Done; };
  my $q = Q-new; POST { $q-Done; };
 
 I like this MUCH better.

So do I, that's why I mentioned it as an advantage of the technique.
As long as the order in which you want the Done()s to be called
matches the order defined by the semantics of multiple POST blocks.

 I'd get rid of the caps on POST if I could, but that would be
 breaking tradition for naming magical things.

Well, we do use lower case "continue".  Perhaps lower-case is just
fine for block-level things.  I did use "always" in the updated
reference implementation.

- The semantics aren't quite the same as "try" [...]

 TMTWTDI.
 
 You could even have
 {
   my $a = new A; POST: $a-Done;
 
   ...;
 } catch { f() } finaly { g() };
 
 (In which case, we go with order-encountered: first the POST, then
 the catch (if approps), then the finaly.

Yes, that's how I did it in the updated reference implementation.

- If the contents of a POST block raises an exception, how
  does it affect other POST blocks?

 I'd like to poist this rule: Each POST block is independent.  If
 one raises an exception, it has no effect on the others (including
 the value of @@).  This is equivlent to saying that each POST
 block has an implicit eval {}.
 
 If you want to do somthing if a POST {} block throws, use POSTs
 inside the POST, or any of the other try {} catch {} finaly {}
 things.

Even easier, in the updated reference implementation I just dyamically
convert a POST into a finally and now all of finally's already well-
defined semantics answer my own question.

  In the example above, if $p-Done throws, then $q-Done
  should be called, *and* vice versa, *and* unwinding should
  propagate if either one threw (or anything else did for that
  matter, unless it was caught without the catching throwing).

 I don't follow you, neccessarly.  Is that what I just said?  I'm a
 little bit behind in the jargon.

It's close to what you just said, with the proviso that you must
keep track of $@ after each of the implied evals and then do the
equivalent of die @$ if any of them were true.  Things are more
complicated with catches, because a catch that doesn't die means
the implied trailing die *doesn't* get invoked after the post
blocks are finished.

 I'd go with a textual FIFO for danglers (what you have proposed,
 if I read it correctly, then a LIFO on the in-body ones in order
 encountered.

That's what I did in the updated reference implementation, except
that I do the in-body ones before the statement-level clauses.

- What about conditional CATCH blocks?  What syntax can we
  use that interacts reasonably well with the rest of Perl?

 Hm?  POST { if (cond) { somthing } }.

 CATCH is just shorthand.

Say the code before the post throws.  Now, if cond is true (and
somthing doesn't throw) you do not want to unwind after the post,
because the exception has been cleanly caught.  But if cond is false
(or somthing does throw) you do, because it hasn't been.  How do you
indicate this using the above notation?  During the RFC process,
there was a great discussion about this, with one camp suggesting
that post/finally shouldn't propagate trapped exceptions, because
you can always do it explicitly in every post/finally you write.
Others considered that to be a dangerous proposal, because of how
easy it would be to forget the re-throw in the common case.

The approach taken by RFC 88 was to work out a syntax and semantics
for multiple conditional catch clauses that still makes the easy
easy the helps make the hard possible.  In the updated reference
implementation, I dynamically convert 

Re: End-of-scope actions: POST blocks.

2001-02-12 Thread Tony Olekshy

"David L. Nicol" wrote:
 
 POST{stuff} is a macro for
 
 push (my) @Deferred_stuff, sub {stuff}; # my on first use in a space

Since the reference implementation requires try, @Deferred_stuff is
actually try's argument list (a bunch of tagged catch and finally
blocks).  The "my" is provided by try.  But in general, yes, if
post/always/except is part of Perl 6 then every block will have to
keep track of whether or not any such action has been seen during
the excecution of the block.  Fortunately, it need do nothing
special if no such actions have been seen (such as, oh, GC for
example).

 and return(arg) becomes, including implied EndOfBlock return:
 
 {shift @Deferred_stuff} while @Deferred_stuff; return(arg)

Yes, but you have to keep track of exceptions raised while
executing {shift @Deferred_stuff}, so you can propagate them
if they occur, and you have to keep track of catch clauses that
don't raise exceptions, because they can terminate propagation.
For example:

my $r = do { except { h() }; f() };
g();
or
my $r = try { f() } catch { h() };
g();

should set $r to f() unless f() raises an exception, in which
case it should use h() for $r, and whether or not f() raises an
exception it should *not* propagate such an exception, it should
execute g().  Unless, of course, h() throws, in which case it
should propagate that exception, not set $r, and not call g().

On the other hand:

my $r = do { always { h() }; f() };
g();
or
my $r = try { f() } finally { h() };
g();

should call h() whether or not f() throws; and if f() or h()
throw the exception should be propagated, otherwise $r should
be set, and g() should be called.

Yours, c, Tony Olekshy