Some Apocalypse 4 exception handling questions.

2002-01-21 Thread Tony Olekshy

In Apocalypse 4, Larry Wall wrote:
|
|   In fact, a CCATCH of the form:
|
|   CATCH {
|   when xxx { ... }  # 1st case
|   when yyy { ... }  # 2nd case
|   ...   # other cases, maybe a default
|   }
|
|means something vaguely like:
|
|   BEGIN {
|   %MY.catcher = {
|   given current_exception() - $! {
|
|   when xxx { ... }  # 1st case from above
|   when yyy { ... }  # 2nd case from above
|   ...   # other cases, maybe a default
|
|   die;# rethrow $! as implicit default
|   }
|   $!.markclean;   # handled cleanly, in theory
|   }
|   }

Beautiful. The synthesis of CATCH, BEGIN blocks, %MY, given, when,
break, dwim =~, die, $!, $!.clean, and $!.stack is awe-inspiring.
The way proto-exceptions, fail, and use fatal work together is also
brilliant.

I particularly enjoyed this one:

   CATCH { when @$! =~ Foo { ... } }

I do have a few questions.

   1. Does this example:

  {
  my $p = P.new;   LAST { $p and $p.Done; }
  foo();
  my $q = Q.new;   LAST { $q and $q.Done; }
  ...
  }

  effectively get compiled into something like:

  {
  my $p;  my $q;
  $p = P.new;   LAST { $p and $p.Done; }
  foo();
  $q = Q.new;   LAST { $q and $q.Done; }
  ...
  }

  If not, how can we evaluate $q in the LAST block if foo() dies?
  Or are LASTs not handled by a magic BEGIN mechanism? Or are the
  LASTs converted into a BEGIN plus some run-time state variable
  that is only set when the LAST is encountered during execution?
  Or am I missing the point entirely ;-?

   2. Consider the following example:

  for my $file ( @files ) {
  my $f is last { close } = open $file or next;
  foo($f);
  CATCH { default { print foo($f) failed\n } }
  }

  The last and CATCH blocks must be invoked at the end of each
  time around the for block, no? Or should I be writing:

  for my $file ( @files ) {
  try {
  my $f is last { close } = open $file or next;
  foo($f);
  CATCH { default { print foo($f) failed\n } }
  }
  }

   3. Would the following execute the Cdie? When do I have to worry
  about accidentally catching control exceptions?

  sub ...
  {
  return if 1;
  fragile();
  CATCH { default { die Couldn't fragile. } }
  }

   4. The test for block exited successfully is C !$! || $!.clean ,
  for the purposes of the block-end handing code, correct?  So

  KEEP is like LAST { if ( !$! || $!.clean ) { ... } }
  and
  UNDO is like LAST { unless ( !$! || $!.clean ) { ... } }

  in which case CATCH is actually like UNDO with an implied given,
  die, and $!.markclean, except it's handled in a different end-
  block order, yes?

   5. What is the order of processing all these special blocks at the
  end of their containing block? Is it:

  1. CONTINUE
  2. CATCH
  3. KEEP
  4. UNDO
  5. LAST
  6. POST

  or some other fixed order, or is there some sort of order-of-
  encounter interleaving of some of the kinds of blocks?

   6. What is the value of

  my $x = try { 1 CATCH { default { 2 } } LAST { 3 } };

  What happens for each permutation of replacing n by die n?

   7. Is there any particular reason why multiple CATCH blocks can't
  simply be queued in some fashion like multiple LAST blocks?

Yours, c, Tony Olekshy





Re: Damian Conway's Exegesis 2

2001-05-16 Thread Tony Olekshy

Felicitations.

Yours, c, Tony Olekshy



Re: End-of-scope actions: Unexpected behavior.

2001-02-27 Thread Tony Olekshy
evelopment of a
module-based mechanism that does work well.  "All this talk about
exceptions" is just work toward nailing down the structural details
of the -language layer, to provide a reasonable working model of
the community perspective to the good folks over at -internals.

Yours, c, Tony Olekshy



Re: End-of-scope actions: Background.

2001-02-14 Thread Tony Olekshy

Peter Scott wrote:

  try {
  die "foo";
  } catch {
  die "bar";
  }
 
  [...]
 
 Surely the first one catches it cleanly since it has a
 "catch-all" catch clause.

That "catch-all" clause throws.  In RFC 88 we said, in the
Definitions section,

Cleanly caught

This means the trapping and handling of an exception did not
itself raise an exception.

So the first one is caught, but it's not cleanly caught.

What's the difference?  Consider try { ... } catch { foo() }.  If
foo() throws then try's exception isn't cleanly caught, so unwinding
*is* propagated at the end of the try statement.  If foo() doesn't
throw the exception is cleanly caught, so unwinding is *not*
propagated at the end of the try statement.

Consider

$r = try { $x / $y } catch { $x / $z };
f();

If $y == 0 you want to use $x / $z for $r and then call f().

But wait, *unless* $z == 0 too, in which case you want to unwind, no?

So, we propagate after an exception if it is not "cleanly" caught.
Just catching it is not enough to terminate propagation, the
catching has itself to be "clean", otherwise there's an exception
in the catch that hasn't been caught.  There's a failure in the
failure handling.  You want to report that, not catch it.  (And if
you do want to catch it, just add clauses.)

Yours, c, Tony Olekshy



End-of-scope actions: Core exceptions.

2001-02-14 Thread Tony Olekshy

Nicholas Clark wrote:
 
 my $f = open $file or die "can't open $file";

 is troublesome. It doesn't report *why* the file can't be opened.

 [...]  *flexible* exceptions are needed

The first version of RFC 88 didn't care what exception objects
were, but discussions in the errors mailing list convinced us that
we should define a base class for exceptions, to guarantee that
certain things are there.  Developers can of course define derived
classes to extend what exceptions can know/do, and the RFC 88 syntax
allows these properties to be used to write conditional catches and
fancier unwinding traceback reports.  An example of such a derived
exception class is included in RFC 88.  See the comments on your
IO layer problem below.

Jarkko Hietaniemi wrote:
 
 Nicholas Clark wrote:
  
  Jarkko would really like
 
print "Foo\n";
 
  in a void context to behave as
 
print "Foo\n" or die $!;
 
 Not just basic I/O but anything 'system': pipe(), system(),
 opendir(), mkdir(), chdir(), fork(), socket(), and so on.

RFC 88 can be used as an exception handling mechanism independent of
whether or not the core uses exceptions to signal errors (whether
in system calls, math operations, or -gasp- the parser).  If the
core does use exceptions to signal errors (whether or not controlled
by a pragma), then RFC 88 says it punts to RFC 80 on the matter of
the details of the derived exception class to be used as the base
for core exceptions.  RFC 88 only requires that the core exceptions
inherit from the base class.  RFC 80 is free to define its own class
hierarchy (things like Exception::CORE::IO::NotFound), and it's own
rules for what information is contained in an exception's message,
and how it is formatted.  These message-building operations can be
overridden for various sections of the core exception class hierarchy.

RFC 88 shows a simple way to do pragma-based conversion of error
modes at the core API (in which case no exception objects, in
the OO sense, need be handled by the bulk of the core), and a simple
way to support both exception-based and return-code-based error
handling modes based on the dynamic value of a pragma, in module
APIs.  Personally, I think we should just use exceptions to signal
errors, and then (1) there's no need for this pragma-based duality,
and (2) you don't have to worry about forgetting to check return
codes (thereby mis-handling failures).

Nicholas Clark wrote:
 
 I'm experimenting with PerlIO layers. If a layer decides it can't
 honour an open due to a reason not covered by errno, it has no way
 of reporting this.

If exceptions are being used to signal errors, your layer can simply
stack an exception that is an instance of a class that inherits
from, say, Exception::CORE::Layer, and those exceptions can track
whatever sort of error-related data you want.  Something like this:

package MyLayer;

sub OperationFoo
{
try {
code that performs operations using layer below me
}
catch {
throw Exception::CORE::Layer::Me::CantFoo
"additional information based on my layer",
other = "info", from = "me too", ...;
}
}

Now, if things go bad in the layer below, when somebody gets
around to telling the user about the unwinding, $@-show will
include messages like the following:

...
Exception::CORE::Layer::Me::CantFoo: additional information
based on my layer.
Exception::CORE::Layer::Low::CantBar: additional information
from lower layer.
...

You effectively have C map { $_-{errno} } @@  available for
all the exceptions raised since the last time an exception was
cleanly caught.

Nicholas Clark wrote:
 
 I think that it would be nice in 5.8 to (optionally on some
 pragma?) make print, close and a few others in void context croak.
 It would actually make writing perl scripts easier. You'd know
 when your disk became full (or you went over quota), albeit in
 with a messy error.  OK, script crashing with an uncaught
 exception isn't nice, but it's nicer than silently losing data
 IMHO.

RFC 88 says, in support of the notion of using exeptions to signal
errors, "How many of us check for IO failures after prints? And if
you're writing a simple program you wouldn't want to have to, but
you would want the program to shut down after a failure if you don't
check."  Also, since you're not returning error codes any more, the
matter of the void context is moot: failures always throw.

Yours, c, Tony Olekshy



Re: End-of-scope actions: Toward a hybrid approach.

2001-02-14 Thread Tony Olekshy

"David L. Nicol" wrote:

 Tony Olekshy wrote:

  If we take this approach then when you just want to casually say
 
  my $f = open $file; always { close $f };
 
  you can.  I like that.  In addition, [...]

 How about "later" instead of "always"

 Because: "later" is a time in the future, but we don't know exactly
 when,

 and "always" has an aspect of continuing in time which is
 distracting (to me.)

The problem may be that a dynamic always statement means both
"no matter what happens" and "not until later".  The static
finally clause just means "no matter what happened" (the effect
is immediate).

For the record, here is the set of keywords for various exception
handling clauses that we culled from the errors mailing list, during
the RFC process, for the Issues list in RFC 88:

raise, always, onException, when, signal, fail, handle,
otherwise, unwind, trap, quit, trip, deal, freak, panic,
cope, punt, ascend, cough, sustain, overrule, and (of
course) longjmp.

(The authors were not recorded, to protect the guilty ;-)

If we want to choose descriptive names, they should be something
like this:

except  on_dynamic_exception_match
always  on_dynamic_end_of_block_scope
catch   on_static_exception_match
finally on_static_end_of_block_scope

or some other arbitrarily long concatenation of concept labels.  In
the end, we'll choose a more reasonable set of names, and quickly
become used to them.  I don't really care what they are, but see RFC
88 for some constraints on the properties they should satisfy.  In
particular, the keywords should not talk about "failure", because
exceptions can in fact be used to signal "success" plus a "get me
out of this mess" longjmp.  As Piers Cawley wrote during the RFC
discussions, "Ah, the 'Bloody hell it worked! That's exceptional'
style of programming." ;-)

Yours, c, Tony Olekshy



Re: End-of-scope actions: do/eval duality.

2001-02-14 Thread Tony Olekshy

Glenn Linderman wrote:
 
 Tony Olekshy wrote:
 
  Traditionally Perl has had both the "do" and the "eval" block
  forms, the latter which traps, the former which doesn't.
 
 In the perl 5 pocket reference 3rd edition page 63, it claims that
 $@ is set to the result of an eval or do.  How does this impact
 exception handling tests on $@ to determine if an exception was
 thrown, if $@ can be set by a do ?  OR is that an error in the
 pocket guide?

The following program

$@ = 0;  eval { 1 };  print '$@: ', $@, "\n";
$@ = 0;  eval { die 2 };  print '$@: ', $@;
$@ = 0;  do   { 3 };  print '$@: ', $@, "\n";
$@ = 0;  do   { die 4 };  print '$@: ', $@;

which produces the following results

$@: 
$@: 2 at ... line 2.
$@: 0
4 at ... line 4.

would suggest that

  - eval{} always touches $@, setting it to undef or some
die's argument, and unwinding (if any) is terminated.

It does not set $@ to the result of the eval.

  - do{} doesn't touch $@ unless the block throws, in which
case $@ is some die's argument, and unwinding begins.

It does not set $@ to the result of the do.

If so, it would appear that the pocket reference has it wrong,
and that the traditional operation of "do" is not affected by the
details of any try/throw/except/always/catch/finally mechanism
that specifies a particular behaviour for $@.  From an exception
handling perspective, "do" is transparent.

Yours, c, Tony Olekshy



Re: End-of-scope actions: Toward a hybrid approach.

2001-02-14 Thread Tony Olekshy

Glenn Linderman wrote:

 Tony Olekshy wrote:
 
  If we take this approach then we know exactly what the following
  code will do.
 
  { my $p = P-new();
 
$p-foo and always { $p-bar };
 
except Error::IO { $p-baz };
}
 
  We also know when the block propagates unwinding; in particular,
  it doesn't if $p-foo raises an Error::IO exception, unless
  $p-baz throws, but it does if $p-foo raises some other
  exception (or if $p-foo doesn't raise an exception and $p-bar
  throws).

 By rule 2 above, it would seem that if $p-foo raises an Error:IO
 exception, that the except block hasn't yet been seen, and
 therefore the block should propagate unwinding.

Ah, yup.  ++$bugs{$self}

 [In RFC 119] The except clause [...] was intended to catch the
 exceptions of only the statement to which it was attached.  I like
 the conditional syntax you have added to the except clause, to
 allow catching only specific exceptions.  However, in making it a
 standalone statement, the semantics change significantly.  As a
 clause, the except clause could be attached to the single
 statement (or block) from which exceptions it was supposed to
 handle might be propagated.  As a statement, however, it seems to
 have acquired a block level scope [...]

I think I know what happened. Back in the 'Assign to magic
name-of-function variable instead of "return"' thread, the
discussion of the dangling always block came up again.  John
Porter pointed out that the difficulty of determining the scope
of the operation is decreased if the always block is placed
inside the block to which it applies, not after it (more below).
I used that notion in proposing the hybrid, and inadvertenly broke
some of the functionality of RFC 119's dangling except block.

 The RFC 119 except clause, which was joined to the prior
 statement, affected only that prior statement.  In other words,
 the except clause and always clause had different relationships
 to the statement to which they were attached.

I'm concerned that I may not understand what you mean by that.
I see two alternatives for the dynamic behaviour of the except
block, which I'd like to try to explain by considering their "try"
dualities.  Then perhaps you can let me know which you mean, or if
I'm still missing something.

Alternative 1:

Start with the following code, as written by a developer:

{ a;
  b except { c };
  d;
  }

Assume, for the sake of discussion, that Perl 6 blocks have
try-like semantics, as if the programmer had written:

try {
  a;
  b except { c };
  d;
  }

Now, after statement a (if it did not throw) and *before* b
(not after it, like an except statement would), Perl dynamically
converts the except block into an equivalent catch clause and
unshifts it onto the try statement's pending clause's list.
From that run-time point on, it's as if we were executing:

try {
  b;
  d;
  } catch { c };

Perl then continues executing statement b.

CONSIDERATIONS:

c is executed only if b or d throw.

Unwinding is propagated if b or d throw,
unless c does not throw.

Alternative 2:

The following code:

{ a;
  b except { c };
  d;
  }

Is the same as:

{ a;
  try { b } catch { c };
  d;
  }

CONSIDERATIONS:

c is excecuted only if b throws.

Unwinding is propagated if b throws, unless c
does not throw.  Unwinding is also propagated
if d throws.

So, given those considerations, is one of those alternatives
the dual of your concept for the dynamic behaviour of the except
block?

Now on to the matter of the scope of the dangling block construct.
I think I understand the "a except { b }" case: the (deferred)
execution of b (iff unwinding) comes into effect just before
executing a.  In the case of:

a and b except { c }

Does the deferred execution of c iff unwinding come into effect just
before a, or just before b (and only if a is true)?  And in the case of:

if ( a ) { b } else { c } except { d }

Does the deferred execution of d iff unwinding come into effect just
before the "if", or just before the "else" (and only if a is false)?
Does this work:

if ( a ) { b } except { c } else { d } except { e }

For reference, here are all the scoping alternatives just discussed,
using try's notation:

try { a } catch { b }

try { a and b } catch { c }

a and try { b } catch { c }

try { if ( a ) { b } else { c } } catch { d }

if ( a ) { b } else { try { c } catch { d } }

if ( a ) { try { b } catch { c } }
else { try { d } catch { e } }

Finally, I'd like to revisit the matter of always.  First consider
the case where always is a dangling block like except.  In such a
case, the following could be written:

$

Re: End-of-scope actions: Background.

2001-02-13 Thread Tony Olekshy

Branden wrote:
 
 There's something I didn't quite understand about RFC 88:
 
 When I
 
 try {
 die "foo";
 } catch {
 die "bar";
 }
 
 I die with "bar", right? But what happens if I
 
 try {
 die "foo";
 } finally {
 die "bar";
 }
 
 I die with "foo" or "bar"? Why is this the right behaviour? Any
 sample code that shows why this should be done this way and not
 the other?

I both cases, since the "foo" exception is not cleanly caught by
either example, unwinding will be propagated at the end of the try
statement.  The code in catch and finally clauses of any outer try
clause (one "containing" the above examples, but not necessary in
the same lexical scope) will see the following:

$@[0] eq "bar" and $@[1] eq "foo" and $@ = $@[0]

with the proviso that the items in the @@ list are actually
exception objects that stringify back to the message passed to die.

In other words, RFC 88 maintains in @@ a stack of all exceptions
raised while in the process of handling and propagating unwinding,
with new exceptions unshifted to occupy $@[0] when they occur.  This
stack is only cleared when exception handling cleanly catches (that
is, a catch clause matches and completes without itself raising an
exception).

Two useful results arise from this technique.

 1) In a catch block, print join("\n", @@), "\n"; effectively
generates an exception stack traceback.  In fact, RFC 88 allows
you to say $@-show with that effect, and supports options for
including things like showing the Perl stack traceback as at the
raising of the first exception (the one in $@[-1]), showing
exeption class names, and/or showing other debug information
only to developers and log files, but not to end users.  That's
how it generates messages like this

UIM.1234: Can't add a new person to the database.
APP.2345: Can't update Company relationship.
DBM.3456: Trouble processing SQL UPDATE clause.
DBM.4567: Unable to write to Locations table.
IOM.5678: Can't open file ".../locations.ndx".
IOM.6789: File ".../locations.ndx" not found.

which I referred to in
http:[EMAIL PROTECTED]/msg05799.html

 2) In the test expression in a conditional catch clause, you can
operate on the entire @@ stack.  For example,

try { ... } catch grep { $_-isa("Foo") } @@ = { bar(); }

will call bar() only if the try block unwinds *and* any of the
exceptions involved in the unwinding are instances of a class
that inherits from Foo.

Similarly, the following two clauses

catch grep { ref $_ =~ /Alpha/ } @@ = { ... }
and
catch grep { $_ =~ /Beta/ } @@ = { ... }

match only if any exception class name matches Alpha, or any
exception's message string matches /Beta/, respectively.
You can also test other exception object properties with
tests of the form

catch grep { $_-{tag} eq "XXX.1234" } @@ = { ... }

Of course, if you're only interested in the most recent
exception, skip the grep operations in these examples and
just test $@ directly (which works because of the rule that
$@ is always equal to $@[0]).

Both of the above results are implemented in the RFC 88 Perl 5
reference implementation (modulo syntax).  There are more examples
at http://www.avrasoft.com/perl6/rfc88.htm#Examples

Yours, c, Tony Olekshy



End-of-scope actions: Background.

2001-02-12 Thread Tony Olekshy

Tony Olekshy wrote:
 
 Damian Conway wrote:
 
  Actually, I do agree that Perl 6 ought to provide a universal
  "destructor" mechanism on *any* block. For historical reasons, I
  suppose it should be Ccontinue, though I would much prefer a
  more generic name, such as Ccleanup.
 
 Perl 6 ought to provide universal exit mechanisms for any delimited
 scope, both for the case of normal sequential termination of scope,
 and for the typically special cases of termination by non-local
 flow control due to stack unwinding caused by the raising of an
 exception.  

Hi, it's me again, the guy who won't shut up about exception handling.
I'm trying, in this message and others under this subject prefix, to
collect these end-of-scope matters into a unified discussion that can
help us maximize the signal to noise ratio when dealing with *both*
unwind trapping and end-of-scope situations during our coding efforts.
This should also make it easier for those who are uninterested in the
topic to avoid the discussion.

Consider the following two cases:

my $f = open $file with_end_of_scope { close $f };

my $y = f($x) but_if_that_unwinds_use { 0 };

These seem simple enough, so what could go wrong?

Consider the following (where Done() is something that should
be done in end-of-scope order, rather than in $p's GC order):

my $p = P-new() with_end_of_scope { $p-Done }

So far, so good.  Now what about:

{
my $p = P-new() with_end_of_scope { $p-Done };
my $q = Q-new() with_end_of_scope { $q-Done };

...
}

Let's see, what should happen after the ...?  Well, $p-Done should
be called, even if the ... started stack-unwinding flow-control.
Maybe $q-Done before $p-Done, but that's a detail.  And then
$q-Done should be called, even if ... or $p-Done starts unwinding.
And if ... or $p-Done or $q-Done starts unwinding, then the
unwinding should be propagated as at the closing curly-brace,
otherwise execution should continue with the next statement in local
flow-control order.

Oops, things just got a little more complicated.

Now before we go any further, a minimalist implementation of all
this is understood; it's called "eval" in Perl 5.  As explained in
RFC 88:

try { may_throw_1 }
catch may_throw_2 = { may_throw_3 }
finally { may_throw_4 }

can be written in Perl 5 like this:

eval { may_throw_1 };
my $exception = $@;
if ($exception) {
my $test = eval { may_throw_2 };
$@ and $exception = $@;
if ( ! $@ and $test ) {
eval { may_throw_3 };
$exception = $@;
}
}
eval { may_throw_4 };
($exception ||= $@) and die $exception;

but the latter solution has a lower signal to noise ratio, it scales
poorly, and it doesn't implement any sort of exception unwinding stack
concept.

Right, so returning to our $p-Done plus $q-Done example, consider
the case where we want to treat specially one of the possible
exceptions that the ... could be unwinding due to.  I'm switching to
RFC 88 notation here, because if nothing else it is pedantic enough
to make my intent relatively clear (hmm).  Something like:

my $result;

foreach ... {

try {
my $p = Framework::P-new( ... );
my $q = Framework::Q-new( ... );

$result = Server::Foo( $p, $q, ... );
}

catch Exception::Framework::Bar {

$result = Client::Fallback( $p, $q, ... );
}

finally { $p and $p-Done(); }
finally { $q and $q-Done(); }

last if $result;
}

What happens if Server::Foo throws an exception and starts
unwinding?  What happens if Client::Fallback does?  What happens
if Q-new() throws an Exception::Framework::Bar exception and
Client::Fallback does *not* throw an exception?  Under what
circumstances does the end of scope propagate an exception
(continue unwinding), and under what circumstances does it continue
with the next statement in local flow-control order?

What happens if Client::Fallback can't open file "Sigma"?  Will
the exception with the message about Sigma get back to the user, 
or will only the most recent message get there (one from $p-Done,
perhaps)?

By now people are asking, if this is so complicated, why not just
keep it simple?  For one thing, it is already the case that the
RFC 88 reference implementation, in Perl 5, does keep the easy
things easy.  The first two examples in this message work as expected
(modulo syntax),  And then, once you look at the effect of a reasonable
set of semantics, you find that less simple constructs do provide
usefull functionality, often helping make the hard things possible
(like really classy error messages, which are in fact somewhat hard
to do).

But why does this matter, since we use exceptions so rarely?
It turns out that there are a number of practioners who have
experimented with

End-of-scope actions: Visibility.

2001-02-12 Thread Tony Olekshy

John Porter wrote:
 
 Tony Olekshy wrote:
 
  I think "always" should be part of an explicit statement, such
  as "try", not some implied property of block structure introduced
  by a dangling clause.
 
 Why?

There's an old engineering joke about instructions that go on and on
for pages about how to attach the cover with the special bolts and
torque them just so and get how to do the x-ray tests and sign off
the job, and somewhere near the end there's a note that says, "before
attaching the cover be sure to test the humdinger transpondence."

Which of the following sets of instructions is better?  These:

1. Skip step one.
2. Kill yourself.
3. Note: if step one was skipped then skip step two.

Or these:

1. Warning: if step two is skipped then skip step three.
2. Skip step two.
3. Kill yourself.

When instructions are written which modify the way other instructions
are to be carried out, the modifying instructions should appear before
the modified instructions.  For humans reading source code that's
"before" in source code order, for CPUs it's in instruction sequence
order.

That's what "eval" and "try" do.  They tell you up front, "Warning,
if the following block unwinds, do not propagate your mind out of here
as you would normally, instead examine the source code following this
block, because trapping is now in effect for the scope of the block."

Trapping is special; it's not like traditional flow control because
it does not involve any in-flow visible source code signal which
indicates to the reader that the implied goto-on-unwind is in effect,
unless we explicitly require something like eval or try.  It's not
like a dangling continue block, because such blocks are triggered by
an in-flow visible statement like next.  That's why [RFC88] quotes
[ESE-1994] to the effect that, "Among the features offered by
programming languages to support exception handling are (1) The
ability to distinguish the normal control flow from the exception
handling flow to make the structure of the program clear [...] Most
early programming languages do not provide specific features for
exception handling, but rather use the normal constructs to implement
it. [...] Obviously this and other ad hoc methods do not satisfy the
requirements listed above."

On the other hand, a post-hoc "always" says, "Note: if you've already
propagated your mind out of here, and you aren't reading this code,
you shouldn't have."  It's like a roadway sign that says, "The section
of road you have just finished driving on may have been slippery if it
was wet."  It's correct.  It's do-able.  It's a poor way to do it.

Yours, c, Tony Olekshy

ESE-1994: The Encyclopedia of Software Engineering, J.J. Marciniak
  (editor), John Wiley  Sons Inc, 1994. ISBN 0-471-54002-1 

RFC 88:   Omnibus Structured Exception/Error Handling Mechanism,
  http://www.avrasoft.com/perl6/rfc88.htm



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



End-of-scope actions: Reference model 2.0.2.1.

2001-02-12 Thread Tony Olekshy

I have extended the RFC 88 Perl 5 reference implementation to
support rudimentary POST and CATCH blocks, for which I've used
"always" and "except" as the keywords.

The new version is http://www.avrasoft.com/perl6/try6-2021.txt
Save that file as Try.pm and perl -we "use Try regress = 1"
to run the regression tests.

All I've done so far is export "always" and "except" subroutines
that splice equivalent "finally" and "catch" arguments into try's
argument list.  This means that, for now, always and except only
work in try blocks, and their error messages are reported as those
of the generated finally and catch blocks.

However, as a result, the following regression tests do work:

!always-1   Always stacks a finally.

try sub {
print "1\n";
always sub { print "3\n"; };
print "2\n";
};

  =expect

1
2
3

!except-1   Except stacks a catch.

try sub {
print "1\n";
except sub { print "2\n"; };
die;
print "BAD\n";
};

  =expect

1
2

And, it does mean that we have a defined semantics for the purpose
of discussion, upon which perhaps we can derive the detailed
semantics for Perl 6's exception handling mechanism.

Please bear with me.  The purpose of this exercise is to make
Perl 6 better, not to make it into my version of Java.  In fact,
I've never programmed in Java.  Thank you very much.  I learned to
appreciate the beauty and elegance of structured exception handling
in Scheme and Object Pascal (one of which is a BD language, one of
which is not).

I'm just trying to figure out how I might be able to make my
miniscule contribution to Perl 6 by writing the exception handling
FAQ.  When I'm explaining

{ f() always { g() except Error::IO { h() } } }

I need to know: does h() get called if f() raised an Error::IO or
only if g() does?

Yours, c, Tony Olekshy



End-of-scope actions: Error messages.

2001-02-12 Thread Tony Olekshy

Johan Vromans wrote:

 [...] As a result, error messages become utterly useless. I almost
 never see a Java program that reports "Cannot open file foo".
 Instead, it reports a java.lang.ioerrorexception and a stracktrace
 of several pages. Useless if you do not have the source, often
 even if you have.

RFC 88 shows how to solve this problem via its built-in exception
unwinding stack, which allows to you generate messages like this
when the exception is punted to the user:

 UIM.1234: Can't add a new person to the database.
 APP.2345: Can't update Company relationship.
 DBM.3456: Trouble processing SQL UPDATE clause.
 DBM.4567: Unable to write to Locations table.
 IOM.5678: Can't open file ".../locations.ndx".
 IOM.6789: File ".../locations.ndx" not found.

You can also display (or not) the stack trace (there's actually more
than one stack trace involved during unwinding, but that's a detail),
depending on whether or not the user has developer access (say) or
not, and include the exception stack and Perl traceback in the system
logs (or not), and include stack traceback and *other* information
that should not be presented to the user but should be presented to
the developer and the logs (or not), all as appropriate to *your*
application.

Might that help?

Yours, c, Tony Olekshy



End-of-scope actions: do/eval duality.

2001-02-12 Thread Tony Olekshy

John Porter wrote:
 
 There is no try, there is only do. :-)

Nonsense.

Traditionally Perl has had both the "do" and the "eval" block
forms, the latter which traps, the former which doesn't.

"try" is just a slightly souped-up "eval" that better handles the
class of problems introduced when exceptions are more commonly
used for error handling (by adding some well-defined auxiliary
clauses to the statement).

Perl has always used an in-flow statement (namely "eval") to signal
an unwind-trapping context; are you *sure* you want to change that
tradition now?

If we work together on this we can make Perl 6's exception handling
something worth having worked on.  If we throw a bunch of untested
ideas together we can only hope they work (at least I hope they work,
since Perl has been my favourite language for the last twelve years).

Now, shall we?

Yours, c, Tony Olekshy



End-of-scope actions: Garbage collection.

2001-02-12 Thread Tony Olekshy

Dan Sugalski wrote:
 
 I do wish people would get garbage collection and finalization split in
 their minds. They are two separate things which can, and will, be dealt
 with separately.
 
 For the record:
 
 THE GARBAGE COLLECTOR WILL HAVE NOTHING TO DO WITH FINALIZATION, AND
 NO PERL OBJECT CODE WILL BE CALLED FOR VARIABLES UNDERGOING GARBAGE
 COLLECTION.
 
 Thank you.

Thank *you* Dan.  I was beginning to wonder if anyone understood.

For the record now, GC is none of your business, you're not
allowed to know how it works (it's a "black box").  Finalization
is handled by try {} finally {}.  Finally.  Finalization.  Get it?

Yours, c, Tony Olekshy



Re: End-of-scope actions: Garbage collection.

2001-02-12 Thread Tony Olekshy

Dan Sugalski wrote:
 
 [...] I wasn't talking about try{}/finally{} stuff. I was talking
 about DESTROY (or its equivalent) for objects, which unfortunately
 can't be tied to any one particular place in the code.

and, from another thread:

 I really don't want to guarantee predictable end-of-block cleanup,
 though, since that means a potentially expensive GC run more often
 than we might otherwise do.

Yes, and I agree with you.  I'm just saying that if we're not going
to automatically guarantee predictable end-of-block cleanup, then I
think we need to provide some way for developers to explicitly
specify predictable end-of-block cleanup (using something like an
always block or finally clause).  Since this explicit operation has
to deal with stack unwinding, and therefore with exception trapping,
this end-of-block cleanup operation has some eval-like semantics.

Therefore, a complete consideration of the matter of end-of-scope
includes not just (1) garbage collection, and (2) DESTROY, but also
(3) the matter of end-of-scope operations explicitly requested by
the developer, in an explicit order which may or may not be related
to GC or DESTROY order, and (4) the matter of the interaction between
explicit end-of-scope operations and explicit conditional exception
handling.

Jan Dubois wrote:
 
 Could you guys please use "destruction" or "cleanup" as the term
 for the end-of-scope processing (see e.g. C++).  Finalization is
 used everywhere else to mean: called by GC before the memory is
 released (see e.g Java/C#).

Thanks for the reminder about the ever-present problem of
conflicting terminology.  I was using "finalization" as a
generic label for various kinds of end-of-scope operations.
I'm not doing it any more ;-)

I think there are three concepts we need labels for, in order to
keep the discussion clear.

  - Code automatically invoked just before an object is finally
garbage collected, whenever that actually happens.

  - Code automatically invoked when an object is finally DESTROYed,
whenever that actually happens.

  - Code automatically invoked when a block scope finally ends,
whether because of local flow-control or because of stack
unwinding.

These are all "end-of-scope" considerations, for various values
of "scope".  They're all about answering the following question:

  When the closing curly brace in { ...; my $p = P-new(); ... }
  is encountered, what happens to the object referred by $p?

Yours, c, Tony Olekshy



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

2001-02-12 Thread Tony Olekshy
 the updated reference
implementation, I dynamically convert "except"s into "catch"s, which
seems to work, so far.

Yours, c, Tony Olekshy



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



End-of-scope actions: Toward a hybrid approach.

2001-02-12 Thread Tony Olekshy

I've been thinking about the effect of the minimalist changes I
made to the RFC 88 reference implementation, and I don't see any
good reason not to support both the static and the dynamic forms
of end-of-block-scope actions.  Consider the following proposal.

 1. Support a try statement (a modified eval) which can have catch
and finally clauses, using the semantics of RFC 88.  If you want
to use catch or finally (instead of always or except) you have
to use try.  These static catch and finally clauses come into
consideration as at when the try is seen, independent of what
happens in the block.

 2. Support always and except blocks.  These constructs may be used
without requiring a try before the block.  They are dynamic
operations which only come into play when they are encountered
in the block, in run-time order.

 3. Implement always and except by converting them into equivalent
dynamically-created catch and finally clauses in the block's
actual or implied try statement.  Then the semantics of always
and except, the details of their effect on exception propagation,
and the details of conditional except blocks, are already
defined (by RFC 88).

If you only want to use always and/or except that's fine, you don't
need the try.  If you don't want to use conditional catches and/or
excepts you don't have to.  We get the advantage of TMTOWTDI, while
keeping the details understandable and relatively simple to
implement by only using one set of semantic rules to cover both
cases.

If we take this approach then we know exactly what the following
code will do.

{ my $p = P-new();

  $p-foo and always { $p-bar };

  except Error::IO { $p-baz };
  }

We also know when the block propagates unwinding; in particular, it
doesn't if $p-foo raises an Error::IO exception, unless $p-baz
throws, but it does if $p-foo raises some other exception (or
if $p-foo doesn't raise an exception and $p-bar throws).

If we take this approach then when you just want to casually say

my $f = open $file; always { close $f };

you can.  I like that.  In addition, when you want to carefully say

my $result;

foreach ... {

try {
my $p = Framework::P-new( ... );
my $q = Framework::Q-new( ... );

$result = Server::Foo( $p, $q, ... );
}

catch Exception::Framework::Bar {

$result = Client::Fallback( $p, $q, ... );
}

finally { $p and $p-Done(); }
finally { $q and $q-Done(); }

last if $result;
}

you can.  I like that too.  Easy easy, hard possible.

The more I think about having both these options available, the
better I like it.  Both allow me to be lazier (the latter in
the case where the exception handling logic is complicated
enough that doing it carefully is actually lazier).  I get the
impression some people think I want verbose code, or some sort
of impractial so-called "ivory tower" solution, but I'm really
just as lazy as you (probably lazier, but we don't want to debate
that here ;-)

Yours, c, Tony Olekshy



Re: assign to magic name-of-function variable instead of return

2001-02-06 Thread Tony Olekshy

John Porter wrote:
 
 [EMAIL PROTECTED] wrote:
 
  Hmmm. If there's such an "always" block, I'd like to see it on
  all blocks, including the continue [1]. But then, it becomes
  hard to figure out to which block the always belongs
 
 That's precisely why these things should be shoved inside rather
 than dangling off the end.  JMHO.

I think "always" should be part of an explicit statement, such
as "try", not some implied property of block structure introduced
by a dangling clause (inside or outside).

Once you have an always clause, it has to be invoked during stack
unwinding caused by the raising of an exception.  This means there
is an implied goto-on-exception pending throughout the scope
affected by the always clause.  This is not like if/else, for, or
while, which are all marked up front, and only have explicit variant
flow control.  It is like eval, but note that eval is marked up
front too.

Like eval, the beginning of the scope for non-local flow control
(such as always and catch) should be explicitly delimited, typically
by using a keyword like try.  Consider the following two cases:

foreach ... { try { ... } catch { ... } finally { ... } }

try { foreach ... { ... } } catch { ... } finally { ... }

now take out the statement keyword and use magic dangling clauses:

foreach ... { { ... } catch { ... } finally { ... } }

{ foreach ... { ... } } catch { ... } finally { ... }

The signal to noise ratio has gone down, no?

In fact, the cross product of these cases and the alternatives for
dangling always block placement produce these four cases:

foreach ... { ... catch { ... } always { ... } }

{ foreach ... { ... } catch { ... } always { ... } }

foreach ... { ... } catch { ... } always { ... }

{ foreach ... { ... } } catch { ... } always { ... }

Now play the problem backwards.  Say you run into one of the
cross-product constructs in some code.  Is it clear to you what
the scope and semantics are?  Is it clear when always applies
to the foreach block, and when it applies to the catch block,
and when it applies to the foreach statement?

What about the try/finally cases?  It's pretty clear, IMHO,
that the catch and finally clauses apply to the try statement,
simply because try is a statement of which they are part.  At that
point, the body of the try block and any previous catch or finally
blocks that are part of the same try statement are apparent.  The
previous blocks are critical, because under various circumstances
blocks need to be triggered by exceptions raised in previous
blocks.

From a psychology of programming languages perspective, wrapping the
whole mechanism up into a statement per se provides the foundation
upon which we can attempt to avoid the conceptual disaster produced
by dangling clauses.  Mixing up traditional sequential flow-control
constructs and non-local stack-unwinding flow-control constructs,
without clearly delimiting what you're doing, is (I think) a less
than optimal idea.

Remember that one of the main uses for catch and always clauses is
error handling (as in, close file if opened even if error during
processing thereof).  I don't like language constructs that obfuscate
my attempts to get error handling right (such as they are) because
errors in error handling tend to make my code behave relatively poorly.

Yours, c, Tony Olekshy

PS: since we're completely off subject, can we continue this under
http:[EMAIL PROTECTED]/msg05604.html



End-of-scope actions, redux.

2001-02-05 Thread Tony Olekshy

Damian Conway wrote:

 Actually, I do agree that Perl 6 ought to provide a universal
 "destructor" mechanism on *any* block. For historical reasons, I
 suppose it should be Ccontinue, though I would much prefer a
 more generic name, such as Ccleanup.

Perl 6 ought to provide universal exit mechanisms for any delimited
scope, both for the case of normal sequential termination of scope,
and for the typically special cases of termination by non-local
flow control due to stack unwinding caused by the raising of an
exception.  Once you have both types of exit mechanisms, getting
the syntax and semantics relatively complete and consistent is
not necessarily trivial.

Many people put a lot of effort into this very problem in the
so-called errors mailing list during the Perl 6 RFC process.
One version of the results, with a fairly complete description
of the matters of dissent that were raised thereto, is contained
in RFC 88, "Omnibus Structured Exception/Error Handling Mechanism",
which I co-authored.

Using RFC 88's notation, the example being discussed in the parent
of this thread would be written something like this:

sub read_it
{
try { my $fh = open @_; $fh }
finally { $fh and close $fh }
}

The existence of the "try" keyword, the choice of other names, and
actually important matters such as the lexical scope of $fh, are
discussed in RFC 88.  More complex constructs that are natural
extensions of the concept are also considered, such as the very
useful case of multiple finally blocks, along these lines:

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

which invokes $q-Done if $q was allocated, even if $p-Done raises
an exception!

Please do consider RFC 88 before re-executing the entire debate on
this matter again.  While many ideas sound good in isolation, gluing
the collection of ideas into a coherent whole can be more challenging.
And, Larry did mention the try catch catch catch finally construct in
his ALS talk.

For your reference, here are some RFC 88 links:

RFC 88 as HTML   http://www.avrasoft.com/perl6/rfc88.htm
RFC 88 as Text   http://www.avrasoft.com/perl6/rfc88.txt
RFC 88 as PODhttp://www.avrasoft.com/perl6/rfc88-pod.txt

Perl 5 Try.pmhttp://www.avrasoft.com/perl6/try6-ref5.txt
Regression Test  http://www.avrasoft.com/perl6/try-tests.htm

Yours, c, Tony Olekshy



On RFC 88: Serendipity while throwing a string.

2000-08-28 Thread Tony Olekshy

I have been working on the Perl 5 reference implementation of
RFC 88 functionality (Try.pm, which is currently available at:
http://www.avrasoft.com/perl6/try6-ref5.txt ), and I stumbled
across the following result.

If you are writing some code, and there is a "throw" subroutine
in scope, and there is a package Exception in scope and it has
a "throw" subroutine, then Perl 5 can tell the following apart
(search for the /!throw-3/ regression test in try6-ref5.txt):

throw "A Message";  # Calls the subroutine.

throw  Exception;   # Calls the method.

throw "A Foo Message",  tag = "ABC.1234";

throw  Exception "Foo", tag = "ABC.1234";

I don't know about you, but I think this is cool.  Talk about
DWIM!  Good old Perl.

So now, in Try.pm, If you throw a string, you get an Exception
anyway:

throw "A Message", ...;

is now the same as:

throw Exception "A Message", ...;

You can't say Cthrow $@ to re-raise an exception any more,
but you can say $@-throw or use a simple bare Cthrow;!
And Cthrow; with @@ == 0 raises a simple Exception!

I'll modify RFC 88 to change the throw syntax from:

throw := throw E message options ;

E := class | object
to:
throw := throw class message options ;
 | throw string options ;
 | throw;

and make the appropriate changes to the semantics.  And of course,
Ctry should accept an additional hook parameter that specifies
the class into which to instantiate string throws.

Seems obvious in retrospect; we already had class and string,
why did E have to be class | object?  Ah well, serendipity
is like that, I suppose.

Yours, c, Tony Olekshy



Re: Structured exception handling should be a core module.

2000-08-26 Thread Tony Olekshy

Peter Scott wrote:
 
 Tony Olekshy wrote:
 
  In fact, not only would I be pleased and honoured to author the
  Perl 6 core Try.pm module, I'm already working on a Perl 5 standard
  reference implementation.
 
  Peter, I think we should make this approach more clear in RFC 88.
 
 I'm not convinced that this can totally be implemented in a
 module.

#- File Try.pm -#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
#
#   Subject:Structured Exception Handling Mechanism for Perl 6
#
#   Purpose:Perl 5 Reference Implementation of RFC 88 functions.
#
#   This is a self-documenting self-testing implementation, in
#   Perl 5, of the functionality referred to in Perl 6 RFC 88,
#   with syntax modified as required by Perl 5.  Save in Try.pm.
#
#   Author: Tony Olekshy
#   Principal Software Architect
#   Avra Software Lab Inc.
#
#   Copyright:  Avra Software Lab Inc, 1999-2000.
#
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#

use strict; $Try::VERSION = "1.0.1.2"; # 2000-08-26

=head1 ABSTRACT

This document assumes a certain familiarity with [RFC-88].

26 regression tests can be found herein at /#- Regress/.

To run the regression tests, use one of:

perl -we "use Try regress = 1"
perl -we "use Try regress = 2"
perl -we "use Try regress = 1, test = 'syntax-1'"
perl -we "use Try regress = 2, test = 'syntax-1'"

If regress = !0 is specified, regression test are run at import
time.  If regress = 2, detailed output is generated, otherwise
successes report as a single output line.  If test = "syntax-1"
is specified, only test "syntax-1" is run (see /!syntax-1/ for
this example).

To run manual tests, perl -w test.pl, where test.pl looks like:

use strict;
use Try;
try sub { throw Exception "Foo" },
catch sub { print "$@[0]\n" };

=head1 DESCRIPTION

use Try;

exception 'Alarm';

try sub {};
try sub {}, catch sub {};
try sub {}, catch "Foo" =sub {};
try sub {}, catch "Foo", "Bar" = sub {};
try sub {}, catch sub {} =   sub {};

try sub {}, finally sub {};

throw Alarm "Can't foo.";

=head1 IMPLEMENTATION

This reference implementation is written for readability,
testability, and distributability.  A production version
would be optimized for performance.  The syntax has been
chosen to make the reference implementation simple, not to
suggest a preferred syntax for the constructs of RFC 88.

The exception, try, catch, and finally "keywords" are exported
to the invoker's package.  Try and Exception packages are
defined, the latter of which contains the base class for
exception objects.

The current unwind stack is kept in @@; $@[0] is current
exception, due to Perl 5 constraints on $@ inside eval.
While unwinding, $@ is join("\n",@@)."\n".

This implementation uses explicit subs in the syntax for try,
catch, and finally clauses, due to Perl 5 parser constraints.

Catch clauses that list exception class names take a list of
quoted-string class names, due to Perl 5 parser constraints.

Lexical scope is not shared between clauses, as per Perl 5.
Clauses are closures, not blocks, so @_ == () therein.
Clauses are eval'd, therefore $@ eq "" therein.  Use $@[0].
Local gotos across unwind-semanitics blocks have not been tested.
Dead-code catch clauses are not currently detected by engine.
Note that: try {}; finally {}; will ignore the finally! It should
be written try {}, finally {};  This would, presumably, be solved
by parser extensions in Perl 6.

Full exception statement functionality is not yet available.

Mechanism hooks are not yet implemented.

=head1 ISSUES

Get rid of the sub on the sub {} terms.

$@ should equal $@[0] inside the clause blocks, not "".

=head1 REFERENCE

[RFC-88] http://tmtowtdi.perl.org/rfc/88.pod
[RFC-80] http://tmtowtdi.perl.org/rfc/80.pod

=cut

# Interface -

package Try;

sub exception { _exception; return undef;  }

sub try   { return _try;   }

sub catch { return (_catch   = @_);}

sub finally   { return (_finally = @_);}

sub Hook  { return _Hook;  }

package Exception;

sub new   { $_[0]-_construct(@_[1..$#_]);  }

sub throw { $_[0]-_throw(@_[1..$#_]);  }

package main;

@@ = ();  # Used for unwind-time exception stack.

# Implementation [ Try ] 

package Try;

$Try::Debug = 0;# Set this to include Try subs in tracebac

Re: Structured exception handling should be a core module.

2000-08-25 Thread Tony Olekshy

Peter Scott wrote:
 
 At 06:48 PM 8/24/00 -0600, Tony Olekshy wrote:
 
 I've read 151 a few times, and I don't understand how it can
 impact the implementation of RFC 88 as a module.  Please explain.
 
 If $@ and $! are merged, then in code like
 
  try {
  system_call_that_fails();
  more_stuff_that_succeeds();
  }
  finally {
  }
 
 does the finally block think there is a current exception or not?
 $!  was set by the failed system call, but nothing died or threw.
 If $@ is put into $! instead, how does the finally block know that
 it's not an exception?  ! ref($!) ...?

I think it is imperative that if Perl has die and eval then it must
have a flag that indicates *only* whether or not eval returned via
normal local flow control or via non-local unwinding started by a
die.  Otherwise, I can see no way any quasi-reliable non-local flow
control can be extened by writing blocks of local flow-control code.

So if open, for example, can set $! without invoking die, then $!
and $@ must not be merged.  As I read it, 151 would (as currently
promulgated) not meet my requirement for the unique nature of a
$@-style variable.  I don't think overloading ref to pick off true
exceptions would make me happy either ;-)

I think that RFC 151 should be *merged* into RFC 80.  RFC 80
should define a simple set of lower-case system-reserved fields
to be used for signalling fault information by the Perl 6 core.
RFC 80 should also define a mapping from this simple fault-hash
into a proper Exception object (using, oh, say reference to a
blessed copy of said fault-hash).

Now, hold on to your hat, %@ should the name of this fault-hash...

$@current exception
@@current exception stack
%@current core fault information

$@[0]   same as $@

$@{type}"IO::File::NotFound"
$@{message} "can't find file"
$@{param}   "/foo/bar/baz.dat"
$@{child}   $?
$@{errno}   $!
$@{os_err}  $^E
$@{chunk}   That chunk thingy in some msgs.
$@{file}Source file name of caller.
$@{line}Source line number of caller.

%@ should not contain a severity or fatality classification.

*Every* call to a core API function should clear %@.

Internally, Perl can use a simple structured data type to hold the
whole canonical %@.  The code that handles reading from %@ will
construct it out of the internal data on the fly.

If Cuse fatal; is in scope, then just before returning, each core
API function should do something like: %@ and internal_die %@;

The internal_die becomes the one place where a canonical Exception
can be generated to encapsulate %@ just before raising an exception,
whether or not the use of such canonical Exceptions is controlled by
a pragma such as Cuse exceptions;.

Yours, c, Tony Olekshy



Re: Structured exception handling should be a core module.

2000-08-24 Thread Tony Olekshy

Peter Scott wrote:
 
 At 06:06 PM 8/24/00 -0600, Tony Olekshy wrote:
 
 In fact, not only would I be pleased and honoured to author the
 Perl 6 core Try.pm module, I'm already working on a Perl 5 standard
 reference implementation.
 
 Peter, I think we should make this approach more clear in RFC 88.
 
 I'm not convinced that this can totally be implemented in a
 module.  Particularly if RFC 151 passes :-)

I've read 151 a few times, and I don't understand how it can impact
the implementation of RFC 88 as a module.  Please explain.

Yours, c, Tony Olekshy



Re: On the case for exception-based error handling.

2000-08-24 Thread Tony Olekshy

Glenn Linderman wrote:
 
 Tony Olekshy wrote:
 
  Glenn Linderman wrote:
  
   actually wrapping a bunch of code inside a try block
   affects how that code reacts to die, thus affecting the
   behavior of the program that previously used die to mean
   terminate the program.
 
  Hang on, this can't be true. To quote from RFC 88:
 
  try { may_throw_1 }
  catch may_throw_2 = { may_throw_3 }
  finally { may_throw_4 }
 
  is exactly the same as (assuming traditional Perl semantics):
 
  eval { may_throw_1 };
  my $exception = $@;
  if ($exception) {
  my $test = eval { may_throw_2 };
  $@ and $exception = $@;
  if ( ! $@ and $test ) {
  eval { may_throw_3 };
  $exception = $@;
  }
  }
  eval { may_throw_4 };
  ($exception ||= $@) and die $exception;
 
  How can this affect how code reacts to die?  It reacts the same
  as with eval, whether wrapped in a try or not.  Say I had:
 
  do_something();
 
  now I wrap it in a try:
 
  try { do_something(); }
 
  this is equivalent to:
 
  eval { do_something(); };
  my $exception = $@;
  $exception and die $exception;
 
  Which is *exactly* the same as bare do_something(); as per Perl 5.
 
 OK, this example clearly demonstrates something.
 
 99% of the catch clauses in the world should be conditional,
 handling only those specific exceptions that it knows about, and
 knows it can handle.  The "catch-all" (unconditional catch of
 anything), is error prone; [...] a "catch-all" might bite off
 _lots_ more than it should chew.  Maybe "catch-all"s that do
 something and then re-throw would be relatively safe.

Yes!

Only when one knows an awful lot about what's going on in the body
of a try is a catch-all that does much more than set a state
variable and re-throw possibly safe, because by definition once an
exception has raised there are a bunch of things one shouldn't make
too many assumptions about.

Here is one possibly safe example:

try { $y = ( $a * $x * $x + $b * $x + $c ) / $d; }

catch { $y = undef; }

but this would be even safer:

try { $y = ( $a * $x * $x + $b * $x + $c ) / $d; }

catch Exception::CORE::Math = { $y = undef; }

The only case where catch really should be unconditional (and not
just re-throw) is when top-level (some sort of main.pl) code wraps
the whole shebang in a try with this type of explicit purpose:

try { the_whole_shebang() }

catch { pass_to_client($@-show(label = 1, trace = 1)) }

Where pass_to_client may be print + exit;

Yours, c, Tony Olekshy



Re: On the case for exception-based error handling.

2000-08-23 Thread Tony Olekshy

Chaim Frenkel wrote:
 
 Tony Olekshy wrote:
 
  If no exception is in scope Perl should continue to generate and
  propagate exceptions (die and $@) as it does now, so we don't
  break tradition.
 
 No, that should be the difference between die and throw. Die is
 immediately fatal. (i.e. current semantics) throw is new and does
 the magic.
 
 We get no breakage that way.

But if die and eval are supposed to do keep doing what they do now,
RFC 88 doesn't impact them at all.  In fact it depends on what they
do now.  To quote from RFC 88:

Although the following code using the new mechanism:

try { may_throw_1 }
catch may_throw_2 = { may_throw_3 }
finally { may_throw_4 }

can be written in Perl 5 like this:

eval { may_throw_1 };
my $exception = $@;
if ($exception) {
my $test = eval { may_throw_2 };
$@ and $exception = $@;
if ( ! $@ and $test ) {
eval { may_throw_3 };
$exception = $@;
}
}
eval { may_throw_4 };
($exception ||= $@) and die $exception;

the opportunity for flow-control errors increases.

On the other hand, if eval is suddenly supposed to stop catching
so-called non-fatal errors, then all hades breaks loose. Trust me.

Yours, c, Tony Olekshy



Re: Exception stack: let's use the @@ list.

2000-08-23 Thread Tony Olekshy

Peter Scott wrote:

 At 10:13 AM 8/23/00 -0600, Tony Olekshy wrote:

 Making throw a method of Exception just means we don't have to say
 
  throw Exception-new("Can't foo.", tag = "ABC.1234", ...);
 
 and it means throw isn't a new keyword, and that throw $@ can,
 invoked now as an instance method rather than a constructor,
 do the right thing.
 
 However, a bare Cthrow doesn't make sense now, because it's a
 method.

 Like I said before, don't let that stop you if you want to make it
 do something; you can just make throw a core function as well as a
 class method.

Yes, clearly. The only difference is that an extra comma is required,
as in:
v
throw Exception = "Can't foo.", tag = "ABC.1234";

sub throw
{
my ($C, $msg, %opts) = @_;

die $C-new($msg, %opts) unless ref $C;

die $C if $C-isa("Exception");

die new Exception::NotException "...",
debug = join(", ", @_);
}

And, who knows what syntax options will be available with Perl 6?

Yours, c, Tony Olekshy



RFC 88 version 2 is available via http.

2000-08-23 Thread Tony Olekshy

I've sent this version to the RFC librarian, but it hasn't shown
up yet.  Until it does, it's available at:

Formatted:   http://www.avrasoft.com/perl/rfc/rfc88v2.htm
POD as text: http://www.avrasoft.com/perl/rfc/rfc88v2.txt

This doesn't include Peter's latest changes yet, none of which
are show-stoppers.  I'll get to their details asap.  I've sent
this copy in its current state because the widening interest in
our little discussion in -erros means people are referring to
v1 of 88 in the RFC index, and v2 has major changes relative to
that.

Yours, c, Tony Olekshy



Re: Exception handling [Was: Re: Things to remove]

2000-08-23 Thread Tony Olekshy

Dan Sugalski wrote:

 Markus Peter wrote:

  There is no such thing as an ultimately fatal error - it should
  always be up  to the user of a module wether the program should
  die, but I guess you see that the same and will answer me with
  "use eval" then ;-)

 I hope you're speaking from a perl level--a segfault pretty much
 spells "Game Over"...

Dan, FYI ~

Yes, from a Perl level.

In general, discussion on -errors have assumed that there will
be a class of what we are generically referring to as exceptions
that will indeed not behave according to the rules for all other
exceptions (such as being able to be caught by eval { ... } ).
Certainly segfault and hcffault (that's halt-and-catch-fire fault)
would we in that class of exceptions.

Other exceptions, such as out-of-memory, might almost be in that
class, except when the emergency out-of-memory memory pool comes
into play.  I haven't though that one through.

Then there's exceptions like divide-by-zero and (if Cuse fatal; is
in scope) cant-open-file.  Clearly, these are catchable.  There is
currently a running dialogue on whether or not divide-by-zero and
other such so-called "fatal" errors should be handled by a separate
mechanism from that used for so-called "non-fatal" errors like
cant-open-file, where is where you stepped in.  Said dialogue will
play itself out.

Yours, c, Tony Olekshy



Re: Exception handling [Was: Re: Things to remove]

2000-08-23 Thread Tony Olekshy

Glenn Linderman wrote:

 Just to point out that fatal is, indeed, as several people keep
 saying, truly in the eye of the catcher.

 That said, none of the currently proposed mechanisms permit
 "resume from fault" semantics, much less "resume from hardware
 fault" semantics.  Sounds like good RFC fodder to me!

Hi, it's me again.  Not to be a pain, but RFC 88 does say:

retry

There has been some discussion on perl6-language-error about the
concept of re-entering try blocks on catch, and the possibility
of using such a mechanism to replace AUTOLOAD.

The author is of the opinion that in order to do this sort of
thing properly one should use continuations, which are being
discussed elsewhere to this RFC.

The intent of this RFC is to provide a simple yet robust
exception handling mechanism that is suitable for error
handling, not for replacing AUTOLOAD.

s/retry/resume/g

I'll try to make that more clear in 88v3d1.

Yours, c, Tony Olekshy



Re: RFC 88: Possible problem with shared lexical scope.

2000-08-22 Thread Tony Olekshy

Peter Scott wrote:
 
 Given that even though we know the shared scope could be implemented,
 the implementors may prefer not to do it.  I would therefore reword:
 
  We would prefer that the blocks share a common lexical scope in the
  way that Ccontinue blocks used to; if this is deemed inappropriate,
  this feature can simply be deleted, and the outer scope can be shared.

I added the following to RFC 88 + ISSUES + Lexical Scope:

The authors would prefer that try, catch, and finally blocks
share the same lexical scope.

Yours, c, Tony Olekshy



Re: On the case for exception-based error handling.

2000-08-22 Thread Tony Olekshy

Chaim Frenkel wrote:
 
 Actually, why not simply unwind the call stack to the routine that
 has the pragma active.
 
 sub foo {use exception; baz()}
 
 sub baz { throw "a fit" }
 
 sub bar {
 no exception;
 foo();
 }

Yes.

 The unwind logic would treat a scope with no exception set _as if_
 each call were wrapped in at try block.

I don't think so.  If no exception is in scope Perl should continue
to generate and propagate exceptions (die and $@) as it does now,
so we don't break tradition.

 PS ***But it's entirely up to each programmer whether or not they use
 PS Fatal-checking***  This is the Perl way anyway.
 
 Fatal checking, is for core functions. And optional for module authors.

Yes.

 Then Fatal.pm and exception.pm could possibly be consolidated.

Yes.

I like something like this

 
 chaim
 --
 Chaim FrenkelNonlinear Knowledge, Inc.
 [EMAIL PROTECTED]   +1-718-236-0183



Re: RFC 88: What does catch Foo { } do?

2000-08-20 Thread Tony Olekshy

Peter Scott wrote:
 
 Tony Olekshy wrote:
 
  Graham Barr wrote:
  
   I am of the opinion that only a class name should follow catch.
   If someone wants to catch based on an expression they should use
  
 catch {
   if (expr) {
   }
   else {
 # rethrow the error
   }
 }
 
  Then you will be glad to know that RFC 88, in the not quite ready
  version two release, allows you do to just that.
 
 "Allows" isn't the same as "should be the only way" though.
 
 Graham, did you base your opinion on usability, parseability, both,
 neither?

And now for a slightly less frisky answer.  The nice thing
about the catch expr = block form is not necessarily
that you can say things like

try { ... } catch $@-{severity} =~ /.../ = { ... }

try { ... } catch grep { $_-isa("Foo") } @@ = { ... }

try { ... } catch ref $@ =~ /.../ = { ... }

but that within the scope of an application's code you can make
available utility functions to allow really nice phrasing of
rule-based catches (without having to re-raise), such as

catch not TooSevere = { ... }

catch AnyException("Error::IO") = { ... }

my $test = sub { lines of predicate based on $@ };

catch $test("Foo") = { ... }
catch $test("Bar") = { ... }
ad infinitum

Is there actually a good reason not to allow this functionality?

Yours, c, Tony Olekshy



RFC 88: Possible problem with shared lexical scope.

2000-08-20 Thread Tony Olekshy

Non-shared:

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

Shared:

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

If P-new throws, then the second finally is going to test
$q, but it's not "in scope" yet (its my hasn't been seen).
Or is it?  If it isn't, I'll take shared lexical scoping out
and put a note about this in ISSUES instead of the current:

If it is not possible to have try, catch, and finally blocks
share lexical scope (due, perhaps, to the vagaries of stack
unwinding), this feature can simply be deleted, and the outer
scope can be shared.

Yours, c, Tony Olekshy



Re: RFC 88: Possible problem with shared lexical scope.

2000-08-20 Thread Tony Olekshy

Peter Scott wrote:

   Tony Olekshy wrote:
  
  try { fragile(); }
  catch { my $caught = 1; }
  finally { $caught and ... }
  

 It should work as though each pair of } ... { in between try { and
 the end of the last finally or catch block isn't there.  Storage
 for lexicals is allocated at compile time, assignment happens at
 run time.

 However, my memory as to what the current perl behavior is was
 faulty; continue blocks do *not* share the lexical scope of their
 attached loop blocks.

 So no, what I'm proposing is not the same as anything currently in
 Perl.  But I think it's a good reason anyway (and why shouldn't
 continue blocks share the same scope?  Not so 'lexical', I
 suppose.  Oh well.)

RFC 88v2d6 now leaves in shared lexical scope and says the following
under ISSUES + Lexical Scope:

If it is not possible to have try, catch, and finally blocks
share lexical scope (due, perhaps, to the vagaries of stack
unwinding), this feature can simply be deleted, and the outer
scope can be shared.

One possible problem is illustrated by this:

try { fragile(); }
catch { my $caught = 1; }
finally { $caught and ... }

If fragile() doesn't throw then finally is going to test
$caught even though the my statement was never exccuted.

These matters will have to be referred to the internals
experts.

Yours, c, Tony Olekshy



Draft 3 of RFC 88 version 2.

2000-08-19 Thread Tony Olekshy

=head1 TITLE

Structured Exception/Error Handling Mechanism

=head1 VERSION

Maintainer: Tony Olekshy [EMAIL PROTECTED]
Date: 19 Aug 2000
Version: 2 (Draft 3)
Mailing List: [EMAIL PROTECTED]
Number: 88

=head1 DRAFT STATUS

This redaction has been modified to reflect Peter Scott's comments
through 2000-08-18.

Areas of development of this document which are not yet complete as
of this draft are annotated with the -- glyph.  This version is not
intended to be the final redaction of this RFC, as there remains
opportunity to enhance the focus and clarity of this document to
the benefit of the reviewers hereto.

The inclusion of a definitions section for terms like propagate,
unwind, exception, and error is under consideration.

This RFC needs to better explain the purpose behind factoring Error
from Exception, an to more clearly explain the matter of RFC 80.

Production editing and spell checking have not been done yet.

=head1 ABSTRACT

"The Encyclopedia of Software Engineering" [ESE-1994] says (p.847):

Inevitably, no matter how carefully a programmer behaves when
writing a program and no matter how thoroughly its verification
is carried out, errors remain in the program and program
excecution may result in a failure.  [...] The programming
laguage may provide a framework for detecting and then handling
faults, so that the program either fails gracefully or continues
to work after some remedial action has been taken to recover
from the error.  Such a linguistic framework is usually called
exception handling.

This RFC describes a collection of changes and additions to Perl,
which together support built-in base classes for Exception and
Error objects, and exception and error handling code like this:

exception 'Error::DB';

try {
throw Error::DB "a message", tag = "ABC.1234", ... ;
}

catch Error::DB { ... }

catch Error::DB, Error:IO { ... }

catch $@-{message} =~ /divide by 0/ { ... }

catch { ... }

finally { ... }

Any exceptions that are raised within an enclosing try, catch, or
finally block, where the enclosing block can be located anywhere up
the subroutine call stack, are trapped and processed according to
the semantics described in this RFC.

The new built-in Error base class is designed to be used by Perl for
raising exceptions for failed operators or functions, but this RFC
can be used with the Exception and Error base classes whether or not
that happens.

Readers who are not familiar with the technique of using exception
handling to handle errors should refer to the CONVERSION section
of this document first.

=head1 DESCRIPTION

 exception 'Error::App::DB::Foo';

Makes Error::App::DB::Foo into a class that inherits from the
built-in Exception class.

If the given name matches /::/, something like this happens:

@Error::App::DB::Foo::ISA = 'Error::App::DB';

and all non-existent parent classes are automatically created as
inheriting from their parent, or Exception in the tail case.  If
a parent class is found to exist and not inherit from Exception,
a run-time error exception is raised.

If the given name does not match /::/ (say it's just 'Success'),
this happens instead:

@Success::ISA = 'Exception';

This means that every exception class isa Exception, even if
Exception:: is not used at the beginning of the class name.

The exception function can also take optional arguments, along
the lines of

exception 'Error_DB', isa = "Error::App";

which results in something like

@Error_DB::ISA = 'Error::App';

Other options may possibly be given to Cexception to control
things like the raise-time stack traceback.

 throw Error::DB "a message", tag = "ABC.1234", ... ;

Throw is both a class and an instance method of the build-in
Exception class.  The indirect object syntax is used to make the
throw imperitive.  As a class method, it is syntactic sugar for:

die Error::DB-new(

message = "a message", tag = "ABC.1234", ...);

As an instance method it is syntactic sugar for copying over
any values given as arguments, and then effecting Cdie $self.
This allows Cthrow $@ to be used to re-raise exceptions.

Note that a derived class can override its constructor to
preprocess the optional arguments, so that (for example) tags
are parsed out of the message, which allows something like this
to work for developers who prefer it (such as the author):

throw MyError "ABC.1234: A message.";

This also illustrates why the message is a required argument
to the throw method.  It should not have to be more complicated
than that to raise an exception of a given type with a given
annotation, in common use.  One should not have to always add

Re: RFC 88 Exceptions, Errors, and Inheritance.

2000-08-19 Thread Tony Olekshy

Peter Scott wrote:

 Tony Olekshy wrote:
 
  That's not what's proposed.  The core and other users would
  use classes derived from Error to raise errors.  Other users
  could even just Error itself.  Exception is reserved for
  exceptions that don't and shouldn't derive from Error.

 I'm still having a hard time with this.  Maybe everyone else
 sees it and can explain it to me.  All I see is, you have a
 mechanism for implementing non-local flow control.  The reason
 the control flow skipped is surely opaque and irrelevant to
 the mechanism?  What the program decides to do with that
 exception, likewise.  Success and failure are more or less
 arbitrary interpretations we place on these exceptions.

I've taken out the concept of a built-in Error class.

It turns out that I really just don't want to have to write

throw Exception::Error::App::DB tag = "ABC.1234",
message = "Can't write to table $table.";

instead of

throw Error_DB "ABC.1234: Can't write to table $table.";

RFC 88 (now, but not until recently) lets me do that via
inheritance, so I now gladly turn all the other built-in
error stuff over to RFC 80 ;-)

  No. I want Error to be able to be extended, over the
  evolution of Perl 6, to include anything that is deemed
  suitable for error handling.  I don't want any of that to
  interfer with base Exception functionality.

Ok, so now I may have to go and turn off something new in a
light-weight class.  I can live with that, as long as RFC 80
keeps this in mind.

Yours, c, Tony Olekshy



Re: Draft 3 of RFC 88 version 2.

2000-08-19 Thread Tony Olekshy

Peter Scott wrote:

 Dave Rolsky wrote:
 
  Tony Olekshy wrote:
  
die
  
   If argument isa "Exception", raise it as the new
   exception and die in the fashion that Perl 5 does.
  
   If argument is a string, wrap it in a new Error
   object, setting the message ivar to the given string,
   and raise that instead.
 
  Actually, the Perl5 die takes a list as its argument and
  does join '', @_ to it to make the actual error message.
 
   If argument is anything else, raise a run-time
   exception.
 
  So this probably shouldn't be the case.

 This sounds alright; there's something very self-defeating
 about raising a run-time exception from dying badly, if you
 see what I mean.

Yes!  That's why v1 of RFC 88 didn't do that.  Thanks, Dave.

 So the third case goes and the second one becomes, args are
 stringified and joined on '', etc.

It now reads:

If passed a single argument that isa "Exception", raise it as
the new exception and die in the fashion that Perl 5 does.

Otherwise, the arguments are stringified and joined with C''
(as in Perl 5), the resulting string is wrapped up in a new
Exception object (setting the message ivar to said string),
and the new Exception object is raised.

Yours, c, Tony Olekshy.



RFC 88 Exceptions, Errors, and Inheritance.

2000-08-18 Thread Tony Olekshy
ather than sounding like I'm sugggesting
it's required.

 Instances of the actual Error class itself are reserved for
 so-called anonymous exceptions, for those cases in which one
 more or less just wants to say Cthrow Error "My message.",
 without a lot of extra tokens, and without getting into
 higher levels of the taxonomy of exceptions.
 
 This is what the user would get by just die-ing.  Let's not
 use 'anonymous'; it makes people think of anonymous arrays,
 hashes,  subroutines, and hence confused.

I'll expunge "anonymous".  We still have Cdie Error-new; to
deal with though.  How 'bout if we call such un-subclassed,
un-parameterized cases "simple" exceptions.

 Although this Exception/Error partitioning has not yet been taken
 advantage of in this RFC, it does provide a good place to help
 make exception handling and error handling into almost the same
 thing, without adversely affecting the functionality of either.
 
 I think this is unnecessary (and we should shorten the RFC so
 that more people will read it).  Leave the whole Error class
 out; that's something separate, as I've said.  I can make RFC
 80 say what you want system exceptions to be.

Well, the partitioninig is about to be taken advantage of, in
88v2d3, by explicitly referencing RFC 80 as the "owner" of the
Error class, independent of the fact that RFC 88 expects it
to inherit from Exception.

  The built-in Exception class reserves all instance variable
  and method names matching C/^[_a-z]/.  The following
  instance variables are defined.
 
 tag
 severity
 message
 debug
 object
 sysmsg
 trace
 
 Why sysmsg?  Why wouldn't a core exception use message?
 Why should someone have to look at both?

The message ivar is for the "end user" message.  The debug ivar
is for additional non-end-user information (for example, in a
web app, internal file names might be considered sensitive
information, but you would still like to get the name of the
file that couldn't be opened into the server log).  These ivars
are part of Exception.

The sysmsg ivar is properly the province of the Error class and
RFC 80, which may want to actually introduce a structured value
here, since $!, $?, and $^E have to all be accounted for.

 Technically, the only ones of these that impact the core are:
 message, and link.  The others might be better broken out into
 another RFC.  One RFC for throwing and handling exceptions;
 another one for what goes in the exceptions.

Link is toast, given @@.  The tag ivar is also in, because of
the namespace managing stuff.  The object ivar is required for
wrapping non-Exception objects (if we keep that functionality
in, otherwise I'd still like to leave it in for Exceptions
that "relate-to" and object).  And while severity and trace are
not strictly required by Exception, it seems reasonable to leave
them stubbed in for polymorphism across Errors and Exceptions.

Yours, c, Tony Olekshy



Re: Draft 1 of RFC 88 version 2.

2000-08-17 Thread Tony Olekshy

Peter Scott wrote:
 
 Tony Olekshy wrote:
 
  trap { $@-{message} =~ /divide by 0/ } catch { ... }
 
 I don't think you need another keyword here.  Just support an
 expression argument to catch and you can do
 
   catch $@-{message} =~ /divide by 0/  { ... }
 
 If it needs to be more complicated, use 'do'; that should
 still make it parseable.  At the very worst it may need a
 comma the way map uses it, which we can write as =.  But I
 don't think that'll be needed.

I do find that a bit hard to parse, but it probably wouldn't be
too bad in practice.  Let's go with it, and then maybe you'll
let me keep finally instead of continue ;-)

I've also added a new ISSUES + Syntax entry, which contains:

If Ccatch EXPR { ... } proves to be difficult for Perl
to parse, then the form Ctrap { EXPR } catch { ... } is
a possible alternative (based on earlier versions of this
RFC).

 Note: I used to favor $_[0] for the exception, but I'm being
 won over to $@.  As long as it doesn't cause problems with
 external interfaces.  Might mention the $_[0] idea in a
 footnote.

Done.

  finally { ... }
 
 Still want this to be "continue"; let's mention both.

It will be included in the alternative keywords table I'm
working on.

  Any exceptions that are raised within an enclosing try,
  catch, trap, or finally block (anywhere up the subroutine
  call stack) are trapped and processed according to the
  semantics described in this RFC.
 
 Maybe it's just me, but I think of 'up' the stack as being my
 callers, and 'down' being my callees.

I had to laugh.  You read the parenthetical as applying to
raising, and I wrote it as applying to the enclosing block!
I've changed it to:

Any exceptions that are raised within an enclosing try,
catch, trap, or finally block, where the enclosing block
can be located anywhere up the subroutine call stack, are
trapped and processed according to the semantics described
in this RFC.

 exception 'Error::DB::Foo';
 
  If the given name matches /::/, something like this
  happens:
 
  @Error::DB::Foo::ISA = 'Error::DB';
 
  If the given name does not match /::/ (say it's just
  'DB'), this happens instead:
 
  @DB::ISA = 'Exception';
 
 I think you want to s/Error/Exception/ above.  Then the rule is
 simpler.  Require all exceptions to be subclasses of 'Exception'
 for clarity.

If I did it that way, then to create an exception error class
derived from Exception, I'd have to call it Exception::Error.
This would mean testing for Exeption::Error::IO::File::Open.

The way it's written above, Cexception 'Error' makes Error a
derivative of Exception, but it's name is Error.  It's a way of
saying that the base class for exception objects is *always*
Exception, even if their name doesn't start with Exception::

  throw Error::DB = "a message", tag = "ABC.1234", ... ;
 
 Suggest dropping the =.  Then throw can be implemented as an
 object method and this is just the indirect object syntax.

I forgot. Earlier yesterday I still needed a subroutine, but
now that I came with the inheritance trick described above,
I don't.  It means we can't just throw to reraise, but as you
mention below, we can just throw $@;  Throw will be a method of
the Exception class and of Exception objects in the next draft.

 Do you really want to leave out the "message =" there?  IMHO
 it looks confusing to tie the class to the message and leave
 the message attribute name out.  So I suggest
 
throw Error::DB (message = "a message", tag = "ABC.1234");
 
 except that my vote is for "code" instead of "tag".

We write a lot of simple throws, most of which would look like
this with the new mechanism as proposed so far:

throw MyDB "ABC.1234: Some message about what went wrong.";

Without the techniques and hooks I've described in 88v2d2, I'd
have to write the following, which has a much lower signal to
noise ratio.

throw Exception::MyDB tag = "ABC.1234",
message = "Some message about what went wrong.";

Even though I want non-local flow-control to stand out with new
keywords, I don't what it to obfuscate and overwhelm the source
code for the algorithms that use it.

And, I really want to encourage people to put an annotating message
on *all* the exceptions they raise; I don't want to make it harder by
requiring the minimal canonical throw form to always have to contain
the message = tokens.

  A throw with no arguments is syntactic sugar for re-raising
  the current exception.  If there is no current exception,
  an anonymous Exception is manufactured first.
 
 Um, I don't like that.  What's an anonymous Exception?  What
 would its attributes be?

An anonymous exception is, literally, the result of a
non-subclassed, non-parameterized, Exception-New().
Under ISSUES + Exception Base Class, RFC 88 v2d1 says:

Default

Re: RFC 63 (v3) Exception handling syntax

2000-08-16 Thread Tony Olekshy

Peter Scott wrote:
 
 If that were so, even without the ignore() function, I could just say
 
  sub Exception::IO::throw { 'do nothing' }
 
 and kill it that way.

Right.  Just like overriding core die.  At that point you can
change the semantics in such a way as to turn your code into
nonsense.

 I am open to suggestions on whether we should make it impossible for
 someone that determined to shoot themselves in the foot to do so.  My
 feeling is that someone smart may have a good reason for doing it (in
 their own code, not in a module given to others), and someone dumb
 deserves what they get for doing something so blatantly stupid.

I agree, we should not make it impossible, but I believe we should make
it relatively difficult to do accidentally (much like the forgotten
re-throw or function return code checking problems).

Yours, c, Tony Olekshy



Re: Towards a reasonable unwinding flow-control semantics.

2000-08-16 Thread Tony Olekshy

Executive summary: I no longer want catch blocks to "daisy chain"
after a exception is thrown in a catch block. Thanks to everyone
who has helped me see the light on this.

Peter Scott wrote:
 
 At 01:16 AM 8/16/00 -0600, Tony Olekshy wrote:
 
  The proposed omnibus Exceptions RFC uses the following three
  rules to guide it while unwinding through the clauses of a
  try statement.
 
 Forgive me for eliding your explanation, but I find it a little
 opaque

Me too, that's why the subject contains the word "Towards".

 Let me advance a model which may be simpler.
 
 1. When an exception is thrown perl looks for the enclosing
try block; if there is none then program death ensues.
 
 2. If there is an enclosing try block perl goes through the
associated catch blocks in order.  If the catch criteria
succeed (the exception class matches one in a list, or a
catch expression evaluates to true, or the catch block
catches everything), the catch block is executed.

If the catch block throws an exception, it becomes the
'current' exception (with a link to the previous one),
otherwise there is no longer a current exception.
 
 3. Whether or not a catch block was executed, the finally
block is now executed if there is one. If the finally block
throws an exception, it becomes the 'current' exception
(with a link to the previous one if there was one).  At
this point, if there is a current exception, go to step 1.
 
 This seems complete and IMHO easily understood.

Yes, that's much better.  Thanks Peter.  Here is a slightly
different version which is still slightly more complex, but
which allows me to more clearly illustrate the change I am
proposing.

  1. Whenever an exception is thrown it becomes the current
 exception (with a link to the previous one if there was one)
 and Perl looks for an enclosing try/catch/finally block.

 If there is no such enclosing block then program death ensues,
 otherwise Perl traps the exception and proceeds as per rule 2.

  2. The relevant try block's next associated catch or finally block
 is processed according to rules 3 and 4.  When there are no
 more blocks use rule 5.

  3. If the criteria for a catch succeed (an exception was thrown
 and either the exception class matches one in a list, or a
 catch expression evaluates to true without throwing, or the
 catch block catches all exceptions), the catch block is
 executed.

 If the catch block and its test expression do not throw then
 the current exception is cleared.  Otherwise, the exception is
 trapped and it becomes the 'current' exception (with a link to
 the previous one).

 Processing continues with rule 2.  [But see below --Tony]

  4. When a finally block is encountered it is executed.

 If the finally block throws an exception it is trapped and it
 becomes the 'current' exception (with a link to the previous
 one if there was one).

 Processing continues with rule 2.

  5. After the catch and finally blocks are processed, if there
 is a current exception then go to step 1.  Otherwise continue
 with the statement after the try statement.

My question is: where should processing continue after rule 3?

The version shown above produces the problem I described before:

  try { } except { } = catch { }
  except { } = catch { }
  catch  { }
 
  The potential problem is that if the first catch throws, then
  the second except will be testing against the $@ from the catch,
  not the $@ from the try.
 
  Is this a problem?
 
 Yes, I think it breaks the intuitive model.

I do too, so the question is what to do about it. I propose changing
rule 3 to add the new paragraph marked with **:

  3. If the criteria for a catch succeed (an exception was thrown
 and either the exception class matches one in a list, or a
 catch expression evaluates to true without throwing, or the
 catch block catches all exceptions), the catch block is
 executed.

 If the catch block and its test expression do not throw then
 the current exception is cleared.  Otherwise, the exception is
 trapped and it becomes the 'current' exception (with a link to
 the previous one).

  ** If a catch test succeeds (or throws), then whether or not the
  ** catch block throws, any succeeding catch blocks up to the next
  ** finally block are skipped.

 Processing continues with rule 2.

This probably means that it should be a syntax error to have any
catch clause follow a non-conditional catch, because such a clause
could never be executed.

 throws() outside a try block are caught by the catch
 blocks of the next enclosing try block.  See above.

Not quite. Throws in a catch block (not a try block per se) still
have to be trapped in order to get to the finally block, if any.
I think you probably meant that, I'm just making it explicit.

The change I descr

Re: Toward an omnibus Perl 6 Exceptions RFC, v0.1.

2000-08-16 Thread Tony Olekshy

Peter Scott wrote:

 Tony Olekshy wrote:
 
 [snip]And the following output was generated:
 
  Exception
 
  $ = Try::throw('Exception') called from scott2.pm[8].
  $ = main::pling('Test') called from scott2.pm[4].
  $ = main::bar('Test') called from scott1.pl[1].
  $ = main::foo('Test') called from scott1.pl[8].
  $ = Try::try(CODE(0xca8830)) called from scott1.pl[9].
  $ = Try::try(CODE(0xca2418), 'catch', CODE(0x10b18ac))
  called from scott1.pl[8].
 
 If I'm not mistaken, exceptions must bubble up through the call
 stack as at the point the exception is thrown, so if we capture
 that stack traceback then, we have all the info.  Do you still
 want the file/line array?

 Yes, I want to be able to get at it Ccaller-like.  You're just
 dumping it.

Ok, but that's just because I was storing it in a string.  Instead
of going to all the trouble to format up the string, we can copy
some of those caller fields into an array (one entry per level) of
hashes (one key per value).  Like this:

$myException-{stackTrace}-[0]-{file}
$myException-{stackTrace}-[0]-{line}
$myException-{stackTrace}-[0]-{sub}

Yours, c, Tony Olekshy



Re: RFC thoughts and guidelines

2000-08-16 Thread Tony Olekshy

On this matter, should something like this be a (meta) RFC?

=head1 TITLE

  Guidelines for Developing Changes for Perl 6 (v0.1).

=head1 ABSTRACT

  - If Perl 5 functionality is not broken (at least for some uses),
then don't change it unless a critical required core change
imples the change in functionality.

  - If other canonical functionality can be agreed on, add that in a
fashion compatible with the existing functionality.

  - If additional functionality can be done in a (core) module, do
it that way unless you have a *really* good argument otherwise.

  - If you can't do it in a module, try to abstract out the minimal
changes to Perl (such as the addition of a well-defined hook)
that will allow it to be done in a module.

  - Make discipline easier to enforce, but don't force any single
model of discipline, which may not be appropriate to some uses
of Perl.

=head1 DESCRIPTION

Case Study 1

Even if we agree on a canonical way to handle "error" exceptions
(those generated by some sort of "failure" in the program flow),
our model may not be suitable for other uses the core functionality
provided by eval {}, die, and $@.  It's nice to be able to do those
other kinds of programs in Perl, too.

Case Study 2

When a topic such as Perl's meta-object protocol generates so much
heat, perhaps it's best not to over-constrain available solutions.
Again, even if we largely agree on a new OO way, our model may not
be suitable for other uses the core functionality provided by bless,
the - operator, and an extensible meta-object protocol.  It's nice
to be able to do those other kinds of programs in Perl, too.

=head1 IMPLEMENTATION

  - Enhance the ability to use a common set of pragmas and modules
across a group of files, so people can't say all those "uses"
are an argument against doing things in modules.

  - Enhance performance of modules, so people can't use that as an
argument against doing things in modules.

  - Add more hooks to Perl and enhance performance of function and
method calls to allow modules to effectively implement additional
low-level behaviour.

Yours, c, Tony Olekshy



Re: English language basis for throw

2000-08-15 Thread Tony Olekshy

"Stephen P. Potter" wrote:
 
 I think fail() and handle() are good.  Something fail()ed and
 it was handle()d by an exception.

Fail is no good, because exceptions can be used to indicate success.
Just because you don't isn't a counter-argument.  Exceptions are
*not* the same as errors, that's just one semantic mapping.

Consider the following case.  You've got some complicated algorithm
that doesn't normally succeed in finding an answer.  When it does
find an answer, it can be all over the place, but no matter what,
you want to stop the algorithm and return the answer.

When you succeed, you want to say

throw Exception::MySuccess object = $answer_object;
not
fail  Exception::MySuccess object = $answer_object;

and then invoke the whole algorithm under:

my $answer;

try { my_algorithm; }

catch Exception::MySuccess { $answer = $@-object; }

If my_algorithm finds the answer then $answer contains the answer,
otherwise $answer is undef.  If my_algorithm throws anything but an
Exception::MySuccess (such as an otherwise uncaught internal Perl
error), the statement after the catch is not executed at all.

That's why all the other words with negative connotation are bad
choices for throw.  It's up to the catcher to determine what's good
and what's bad, not the thrower.

The "classical" uses of try/throw/catch/finally have been around
for many years.  During that time, many languages have incorported
the concepts, and after much heat and little light, the terminology.
Could it be that's because, *all* things considered, it is good
terminology?

Consider "finally" vs. "always".  Always?  Even if force majeur?
Finally simply means, "as the final act of the unwind processing".

By the way, this discussion has moved to perl-language-errors, so
the good folks here at perl-language-flow can concentrate on finding
silly words for other Perl flow-control constructs ;-)

Yours, c, Tony Olekshy



Re: Exceptions and Objects

2000-08-14 Thread Tony Olekshy

Jonathan Scott Duff wrote:
 
 On Sun, Aug 13, 2000 at 07:27:47PM -0700, Peter Scott wrote:
 
  An error has text associated with it, but also a bunch of other
  attributes.
 
 So it's a structured data type... where does OOP come into play?

 1. It allows you to *extend* the base type with new attributes
without having to re-implement all the base attributes.

 2. It allows you to *extend* the base type with new methods that
can, say, compute predicates based on the object's attributes.
Then, you can say things like:

if ( $@-isa(MyException)  $@-CanFoo ) { ... }

 3. Is allows you to *override* base class behaviour, for example,
by changing the way stringification works for some classes, or
by modifying a constructor to do some sort of logging, for some
class of exceptions.

  They fall naturally into different classes, some of which have
  subclasses (a File error is-a IO error).
 
 This, to me, seems a mere matter of naming.  Was it that OOP already
 had a hierarchical naming system and so it was used?

Once the other good reasons for OO exceptions come into play, you
may as well take advantage of the serendipity.

 What does it mean for an exception to have semantics?  When an
 exception is thrown does something special happen whether it's
 caught or not?

$@-CanFoo is an example of semantics that determines whether or
not the exception is caught; stringification may be an example
of semantics that comes into play when an exception is caught.

Yours, c, Tony Olekshy



Re: Exceptions and Objects

2000-08-14 Thread Tony Olekshy

Piers Cawley wrote:
 
 Tony Olekshy writes:
 
  Peter Scott wrote:
  
   An exception is an 'error'.  That's already a vague concept.
 
  I'll say it's vague.  There are certainly uses for an exception to
  trigger non-local success, not an error at all.  In fact, there are
  whole programming techniques based on such uses.  Just because most
  of us usually use exceptions to handle errors, that doesn't mean
  Perl should not support other uses.
 
 Ah, the 'Bloody hell it worked! That's exceptional' style of
 programming?

Yup. But I couldn't have said it better than you just did.

Yours, c, Tony (TIMTOWTDI) Olekshy



Re: Exceptions and Objects

2000-08-14 Thread Tony Olekshy

Jonathan Scott Duff wrote:
 
 On Mon, Aug 14, 2000 at 04:09:41AM -0600, Tony Olekshy wrote:
 
  $@-CanFoo is an example of semantics that determines whether or
  not the exception is caught; stringification may be an example
  of semantics that comes into play when an exception is caught.
 
 Ah, this is why I started asking I guess.  Some people were proposing
 a try/catch like the following:
 
 try { }
 catch SomeException { }
 catch SomeOtherException { }
 finally { }
 
 which seems to only catch exceptions based on name.  Which implies to
 me that, for exceptions to have useful semantics, they'd have to be
 rethrown after they're caught.  I like the following, but it would
 also seem that exceptions that aren't handled here would have to be
 rethrown so that an upstream catch could handle them.
 
 try { }
 catch { # ALL exceptions
 switch ($@) {
 case ^_-name eq 'IO'   { ... }
 case ^_-canFoo { ... }
 throw $@;   # No cases matched, rethrow
 }
 }
 finally { }

This is why RFC 88 is working on syntax and semantics for:

try { ... } except sub { $_[0]-CanFoo } = catch { ... }

which *does* unwind if $_[0] can't Foo (or, if $_[0]-CanFoo or the
catch clause throws).

Yours, c, Tony Olekshy



Re: errors and their keywords and where catch can return toand stuff like that

2000-08-14 Thread Tony Olekshy

Evan Howarth wrote:
 
 Tony Olekshy wrote:
 
  Just be sure to arrange to handle exceptions while handling
  exceptions.
 
 Are you saying that the try-catch proposal automatically
 handles exceptions thrown in catch and finally blocks?

Yes.

 That's an interesting idea. Java, C++, and Delphi don't do
 that for you. They expect the programmer to either avoid
 or correctly handle exceptions in catch and finally blocks.

Right, and in practice, it drives me nuts, because if I have
a try, a conditional catch, and a finally, I want the finally
to happen whether or not the code in the catch throws.

 How does try-catch handle exceptions in catch and finally
 blocks. Does it just eat them?

The basic syntax considered in RFC 88 is:

try { ... throw ... }   #  try clause

except TEST = catch { ... }#  0 or more

catch { ... }   #  0 or more

finally { ... } #  0 or more

unwind { ... }; #  0 or 1

The basic semantics are:

  * The try clause is evaluated.

  * Each catch clause is invoked, but only if an exception has
been raised since the beginning of the try statement, and
the catch clause's except TEST is true or is not given.

  * Each finally clause is invoked whether or not an exception
has been raised since the beginning of the try statement.

  * The unwind clause, if any, is invoked if an exception has
been raised since the beginning of the try statement, and
it has not been cleanly caught.

  * After processing all clauses, try unwinds (dies) iff any
exception wasn't cleanly caught.

An exception is considered to be "cleanly caught" if it was in
the try clause, and it triggered a catch clause, and no catch
or finally clause raised an exception.  There are some other
semantics that come into play with multiple catch clauses, for
detailed information see RFC 88.

Yours, c, Tony Olekshy



Re: errors and their keywords and where catch can return toandstuff like that

2000-08-14 Thread Tony Olekshy

Peter Scott wrote:
 
 Tony Olekshy wrote:
 
  When you want the first one, use try + catch.
 
  When you want the second one, use eval, then manipulate $@.
  Just be sure to arrange to handle exceptions while handling
  exceptions.
 
 Erk, people shouldn't have to use such radically different
 syntax for a tiny semantical change.

They don't have to.  They can just use a try with an empty catch,
which is what Peter and I wanted in the first place.

I was only pointing out that there are two camps involved here,
one of which likes eval semantics and the other which likes try
semantics.  If we leave eval alone in Perl 6, and add try, then
everyone should be happy, and there will be one less potential
problem converting Perl 5 code.  We may need not even need to add
try to the Perl guts (RFC 88 as implemented in Perl 5 is a module
that adds try, so perhaps all we need is a core module and possibly
an efficiency hook or two).

 Everyone seems to have started thinking about the implication of
 inheritance in exception classes at the same time.  Whatever the
 default behavior is, we can easily change it on a global basis
 (using Chaim Frenkel's sub name here);
 
 sub Exception::uncaught_handler { maybe rethrow, maybe not }
 
 Or a per-class basis:
 
 sub Exception::IO::uncaught_handler { ... }
 
 Or a per-object basis (gross as I find this):
 
 my $e = Exception::SQL-new(...);
 $e-uncaught_handler = sub { ... }
 throw $e;
 
 And the dispatcher would look first in the object, then in the
 class for uncaught_handler.

Ideas about exceptions and exception handling are easy.  Getting a
suite of ideas to cooperate in practice can be more difficult.  For
example, with

try   { throw Exception1-New; }
catch { throw Exception2-New; }

does the uncaught_handler of Exception1 get called?  One could say,
"no, because it was caught", or "yes, because it wasn't fully
caught, because the catch didn't complete".

And by the way, what's supposed to happen when an uncaught_handler
throws?

I'd like to see some working code excercising uncaught_handler, with
documentation and regression tests I can study.  One could base such
an implementation in the code referenced in RFC 88.

 I think it's cool how this process is converging :-)

Yes, but let's not get carried away.  We have to try to come up with
a clean set of basic concepts that work well in the easy easy, hard
possible sense.  If we want to use unwinding with exception objects
as the basis for Perl's failure handling, then we *certainly* don't
want a fragile exception handling mechanism compounding the failure
for us.  What is the cost of an accidentally lost throw when you are
using exception handling for error handling?  As Henry Spencer used
to say, "then all bets are off".

If you don't like food-for-thought digressions, skip this paragraph.
Say you and I are playing a game of catch (the verb).  We can throw
a football, or a baseball, or a frisbee, all using the same basic
throwing and catching mechanism.  We can teach that mechanism how to
handle different classes of throwable-catachables, but we can't
teach it to throw or catch 16T blocks.  And in no case is the object
being thrown allowed to reach out and change my hand into a foot.

Yours, c, Tony Olekshy



Re: errors and their keywords and where catch can return toandst uff like that

2000-08-14 Thread Tony Olekshy

Peter Scott wrote:
 
 If anyone suggests that
 
  try {  }
  catch Exception::Foo, Exception::Bar { ... }
  catch { exception thrown here causes it to
  start going through catch blocks again }
 
 then I'm afraid I'm going to have to turn to drink.

Agreed.  However, consider this:

try { may_throw_1; }
catch   { may_throw_2; }
catch   { may_throw_3; }
finally { may_throw_4; }

Under what conditions should the second catch clause be invoked?

Under what conditions should the above unwind after finally (vs
continuing the normal order of execution?  RFC 88 currently goes
into the second catch if the first catch throws, but perhaps it
should go straight to the finally if any catch throws.

Or maybe not. Consider this case (in pseudo-syntax):

my $o = SomeClass-New;

try { f ($o); }

catch $@-ImpliesFooCleanup { $o-AttemptFooCleanup; }
catch $@-ImpliesBarCleanup { $o-AttemptBarCleanup; }

finally { $o-Done; }

If you would want to attempt bar cleanup even if attempting
foo cleanup fails (throws), then RFC 88 gets it right (the
syntax is different, and the unwind stack is used to prevent
the second exception from hiding the first one, but it works).

We either have to disallow multiple and conditional catches
and move everything to a catch-all block and do all the
flow control manually (for which we already have eval {}),
or we have to specify the semantics for multiple conditional
catches.

Yours, c, Tony Olekshy



Re: RFC 92 (v1) Extensible Meta-Object Protocol

2000-08-13 Thread Tony Olekshy

"Randal L. Schwartz" wrote:
 
 Tony Olekshy wrote:
 
  Perl should be modified so that if C$ISA::Search (or equivalent)
 
 Do you mean "$YOUR_PACKAGE::ISA::Search"
 which is in the package "YOUR_PACKAGE::ISA"?
 
 This would be the first time (to my knowledge) that something would
 be in an unrelated package.  Remember... there is no necessary
 correlation between $A and $A::B as of yet.  Your proposal would
 breach that.

Oops, sorry.  That's what we do (aka get away with) in our little
generator module, but I can see that it doesn't scale well.

 Presuming the rest of the idea is deemed sound enough to implement
 (:-), I'd strongly suggest the variable name be something like
 $ISA_SEARCH or something like that, to keep it in the same package.

Hmm, what about %ISA{Search}?  Then, if we identify other meta-object
protocol hooks (or parameters) we could specify them via other entries
in %ISA.  Meanwhile, @ISA could stay the same.

I'm not too worried about the details at this point.  However, what I
would like is for a subset of Perl 6 to almost indistinct from Perl 5:
additions are ok, extensions are ok, but I'd rather not rewrite all
the Perl code in the world just to handle someone's idea of what Perl
should have been if they were in charge ;-)

I also would rather not be forced to use someone else's inextensible
definition of OO that is too simple or too complex for my needs.
Perl's got a good start on a very minimalist OO protocol.  Let's make
the minimal visible fixes we can to that, the maximal fixes to making
it efficient, and the necessary fixes to make it more easily and
compatabily extensible, so that multiple OO protocols can interoperate
in the same program.

Yours, c, Tony Olekshy



Re: RFC 63 (v2) Exception handling syntax

2000-08-12 Thread Tony Olekshy
 is the key, and the exceptions are just
what you happen to be handling.

We should be able to do a pretty good job of putting these two
perspectives together into binocular vision (-; | ;-)

Yours, c, Tony Olekshy



Re: RFC 95 (v1) Object Classes

2000-08-12 Thread Tony Olekshy

Andy ~

Since you didn't mention it in your references, you may want to
check out RFC 92, Extensible Meta-Object Protocol -- Method Search
at http://tmtowtdi.perl.org/rfc/92.pod

RFC 92 considers an existing Perl 5 module we have that allows
us to write code like the following, and it considers how to make
Perl 6 better support this kind of extensibility via modules (rather
than via new core functionality forced on us all).

package MyClass; use Prothos::Class ISA = ParentClass;

ivar Foo = Public,Write   = Private;
ivar Bar = Private,   Default = "Hello, World";
ivar Baz = Protected, Default = {};  # Hash ivar.

method HelloWorld = Public, sub
{
my ($I, %A) = @_;

$I-Baz(Name = $A{Name}); # Ivar accessor.

print $I-Baz("Name"), " says \"", $I-Bar, ".\n";
};

method Cogitate = Private, sub
{
...
};

method OverrideMe = Protected, Bind = Virtual, sub
{
...
};

Our little class generator does the things we need, without taxing
our conceptual notion of what Perl OO looks like.  As far as I can
tell, RFC 95 doesn't do the things we need, while taxing our notion
of what Perl OO looks like.  So I guess you can chalk up my comment
to be "skeptical", at least for now.

Yours, c, Tony Olekshy



Re: RFC 80 (v2) Exception objects and classes for builtins

2000-08-12 Thread Tony Olekshy

Peter Scott wrote, in RFC 80 (v2):

 =item id
 
 Unique numeric identifier, assigned by perl developers.

I'm loath to bother everyone with this, but to me the id of an
object should be unique to each *instance* of the class.  If we had

my $e = Exception-New(id = "ABC.1234");
my $f = Exception-New(id = "ABC.1234");

then $e and $f would have the same id, but be different objects.
In RFC 96 I've proposed called this attribute the "tag", in the
sense of those little paper labels tied to merchandise with a
string or the little embossed metal plate attached to a motor or
to a pressure relief valve (that's what mechanical engineers call
them).

If we really want an id attribute, I think it should be "$self"
or ++$foo for some base-module lexically scoped $foo.  I can't
think of any practial use for it right now, but that certainly
doesn't mean there can't be any.

 Line number exception was thrown at.
 File exception was thrown in.

Should this be line thrown at or line constructed at?  Does anyone
care?

 =item data[(userdata)]
 
 User data, arbitrarily complex.  If the user knew the underlying
 object implementation, of course they could stick in attributes
 with any names they wanted; but nothing should rely on that, so
 this hook is provided.

Something like this is probably a good idea, but as noted in RFC 96,
"How to extend ivars and control namespace?".

 Stringifying the object itself will yield the Cmessage attribute.

Or perhaps a formatted combination of a subset of the attributes,
as in RFC 96?

 A Cfacility attribute was suggested to indicate what part of
 perl is throwing the exception: IMO that is covered in the
 exception class.

Agreed.

Yours, c, Tony Olekshy



Re: RFC 80 (v1): Exception objects and classes for builtins

2000-08-11 Thread Tony Olekshy

I've moved this from perl6-language to perl6-language-flow.

Tony Olekshy wrote:

 With the approach proposed in RFC 88 (Structured Exception
 Handling Mechanism), you could write that as:

   try {
   } catch {
   switch ($_[0]-name) {
   case IO { ... }
   case Socket { ... }
   }
   }

Graham Barr wrote:
 
 the error are objects, so you need to allow for inheritance.

I was just trying to point out that RFC 88 uses try {} catch {}
instead of try {} otherwise {}, and that the current error comes
into the catch block via @_ (as in RFC 63), so one doesn't need a
"global".

Sometimes you want to collect all the catching into one clause (if,
say, there was lots of common code and little varying code).  In
other cases, you want a seperate clause for each exception (if, say,
there is little common code, then the seperate clauses handle the
switch for you, which is more DWIM).  That's why RFC 88 allows you
any combination of these operations, as in:

try {
}
except isa = "Foo" = catch { ... }
except isa = "Bar" = catch { ... }
except else = catch { ... }

Again, the differences between this and RFC 63's approach are, in
this case, only syntactic.

Yours, c, Tony Olekshy



Re: RFC 80 (v1): Exception objects and classes for builtins

2000-08-11 Thread Tony Olekshy

I've moved this from perl6-language to perl6-language-flow.

Graham Barr wrote:

 eval {
 # fragile code
 }
 else {  # catch ALL exceptions
 switch ($@) {
 case __-isa('IO') { ... }
 case __-isa('Socket') { ... }
 else   { ... }
 }
 }
 continue {
# code always executed (ie finally)
 }

Chaim Frenkel wrote:

 Nice.

Hmm.  The eval was commented to indicate fragile code, which is
implied if the keyword try is used.  The else was commented to
indicate a catch, instead of saying catch, and the continue was
commented to indicate a finally, instead of saying finally.

There does seem to me to be some benefit to the clarity of the
RFC 88 approach, which supports both:

try { }
except isa = 'IO' = catch { }
except isa = 'Socket' = catch { }
except else= catch { }
finally { }

and:

try { }
catch {
switch ($_[0]) {
case __-isa('IO') { ... }
case __-isa('Socket') { ... }
else   { ... }
}
}
finally { }

Yours, c, Tony Olekshy



Re: RFC 80 (v1): Exception objects and classes for builtins

2000-08-11 Thread Tony Olekshy

Peter Scott wrote:
 
 John Porter wrote:
 
  Which makes me think that it would be nice if the continue block
  could come before the catch block(s).
 
 I get where you're going with this but it breaks the paradigm too
 much.  Now you need a 'finally' block again.

Sometimes you want before, sometimes after, as in:

try {
open(*F, "foo") or throw "Can't open foo.";

print F ...;
}

finally { close F or throw "Can't close foo."; }

unwind { attempt_to_log_error_message($_[0]); }

which can also be written as:

try {
try {
open(*F, "foo") or throw "Can't open foo.";

print F ...;
}

finally { close F or throw "Can't close foo."; }
}

catch { attempt_to_log_error_message($_[0]); throw; }

The exception handling mechanism considered in RFC 88 has both
pre-finally and post-finally exception trapping clauses, named
catch and unwind.

The basic syntax considered in RFC 88 is:

try { ... throw ... }   #  try clause

except TEST = catch { ... }#  0 or more

catch { ... }   #  0 or more

finally { ... } #  0 or more

unwind { ... }; #  0 or 1

The basic semantics are:

  * The try clause is evaluated.

  * Each catch clause is invoked, but only if an exception has
been raised since the beginning of the try statement, and
the catch clause's except TEST is true or is not given.

  * Each finally clause is invoked whether or not an exception
has been raised since the beginning of the try statement.

  * The unwind clause, if any, is invoked if an exception has
been raised since the beginning of the try statement, and
it has not been cleanly caught.

  * After processing all clauses, try unwinds (dies) iff any
exception wasn't cleanly caught.

An exception is considered to be "cleanly caught" if it was in
the try clause, and it triggered a catch clause, and no catch
or finally clause raised an exception.

Yours, c, Tony Olekshy



Re: RFC 80 (v1): Exception objects and classes for builtins

2000-08-11 Thread Tony Olekshy

Chaim Frenkel wrote:

 [ ... ] for me polymorphism is action-at-distance of the worst
 stripe.  Its the cheap and dirty way of doing OO. [...] I see
 very little reason to have two methods with different signatures.

Method signatures and polymorphism are orthogonal.  The latter
refers to different classes having differing implementations of
a method of the same name (often via inheritance and overriding)
and/or name + signature.

Say you had a base class for exception objects that defines a
method that returns whether or not Foo is true for that class.
Say you derive a descendent class from that base class via
inheritance, and then extended the derived class to add a new
instance variable.  Say you then, in your derived class, override
the method that returns whether or not Foo is true to take your
new instance variable into account.

With polymorphism, one doesn't have to know whether one has an
instance of the base class or an instance of the derived class
(using kludgery such as isa), one can just say $o-IsFoo and
both cases work as per Fooing.

Signatures don't need to enter into it.  For more information see
http://www.cyberdyne-object-sys.com/oofaq2/body/typing.htm#S2.1

Yours, c, Tony Olekshy



Re: RFC 85 (v1) All perl generated errors should have a

2000-08-10 Thread Tony Olekshy

Chaim Frenkel wrote:

 [stuff about exception numbering]

 Hmm, I thought I saw another exception RFC pass by.
 Yup, RFC 88, Tony Olekshy [EMAIL PROTECTED]

 Could you two folks get together and hash this out.

RFC 88 goes to some trouble to seperate exception handling from
exception objects.  It doesn't care how exception objects are
numbered, labelled, or titled; it only cares how they stringify
and isa.

However, RFC 88 does say:

  If Try's notions of the seperation of exception handling from
  the implementation of exception objects gains credence, there
  will need to be one or more RFCs on the matter of the built-in
  or core-module Exception class sanctioned by Perl 6.

RFC 88 does provide a minimalist exception object base class, but
it doesn't consider the manner in which this is extended, such as
for numbering, labelling, or source-code tracking.  It also doesn't
consider the class hierarchy for exception objects.

I will however be delighted to participate in the discussion of
RFCs related to Perl 6's canonical exception class.  We should
probably move to [EMAIL PROTECTED]

Yours, c, Tony Olekshy