Re: 'catch' statement modifier

2003-11-23 Thread Tony Olekshy
Luke ~

These matters are covered at some length in RFC 88 and Apocalypse 4.

http://www.avrasoft.com/perl6/rfc88.htm

http://www.perl.com/pub/a/2002/01/15/apo4.html

Yours, &c, Tony Olekshy

Luke Palmer wrote, at 2003-11-23 11:55:
> 
> I was reading over some code that used the MIDI module, and saw the
> C method.  I began wondering, how does one report the
> error if he feels like it, but let the module report the error if not,
> in a concise way.
> 
> What about something along the lines of a C statement modifier,
> like:
> 
> $opus.write_to_file($file) catch die "Couldn't write to $file: $!\n";
> 
> Which would be equivalent to:
> 
> try {
> $opus.write_to_file($file);
> CATCH {
> die "Couldn't write to $file: $!"
> }
> }
> 
> It doesn't read quite as nicely as I'd like, but I think it could be a
> very useful notation.  After all, if I have to type a lot when I'm
> handling errors, I'll prefer not to handle them at all.
> 
> Which reminds me, if you throw an exception inside a CATCH block, does
> it propogate outside to be caught by other CATCHes in the same block
> that are lexically lower, or does it propogate outside of the enclosing
> scope.  That might be a little confusing... for example:
> 
> try {
> try {
> do_something();  # Throws
> CATCH { die "Foo" }
> CATCH { die "Bar" }
> }
> CATCH { print "$!" }
> }
> 
> Does that print Foo or Bar?
> 
> Luke
> 
> 




Some Apocalypse 4 exception handling questions.

2002-01-21 Thread Tony Olekshy

In Apocalypse 4, Larry Wall wrote:
|
|   In fact, a C 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 C? 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
ns to use exceptions
  for signalling errors.

The one thing we don't want on this front in the design of Perl 6
is some half-baked concept of exception handling that (1) doesn't
work well in production, and (2) prevents the development 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: 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 

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

"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



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: 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



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

2001-02-14 Thread Tony Olekshy

Dan Sugalski wrote:
> 
> Tony Olekshy wrote:
> >
> >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).
> 
> Attributes or other things stuck on the end of blocks strikes me as
> a messy sort of way to do this. Why not something simple like
> GC::cleanup or GC::collect, to explicitly cleaning up after
> destructable objects and collect garbage memory respectively?

Hmm, I think we still have a terminology impedence mismatch here.
It's probably my fault.  When I said "end-of-block cleanup",
I didn't just mean DESTROY and/or GC.  Consider the following:

{
my $p = P->new;

try { $p->foo } finally { $p->bar };

$p->baz;
}

There's an explicit end-of-block "cleanup" operation for the try
block, namely $p->bar, which is called whether or not $p->foo throws.
Then, iff neither $p->foo nor $p->bar throws, $p->baz is called.
Then (whether we're now unwinding or not) there's an end-of-block
cleanup operation for the anonymous block, but this an implicit
end of lexical scope cleanup for $p (not an explicit finally clause
or POST block), so if $p's object's refcount is 1, or it is found
in some sort of sweep, then DESTROY and garbage collection can be
considered.

Meanwhile, I agree that try/finally (or any similar such explicit
exception handling mechanism) is not an appropriate way to talk
about GC, more strongly, I think the two mechanisms should be
explictly decoupled.  (Personally, I don't think developers should
expect implict cleanup to be guaranteed to happen immediately,
and I don't think the Perl 6 designers should be so constrained,
but that's probably just because I've structured my code so as
to obviate the need, and therefore don't appreciate it.)

I only mentioned try/finally in the GC thread to note that if
we use a mechanism like that to handle explicit end-of-scope
problems, then you guys are free to do whatever you want with
DESTROY and GC, without having to worry about explicit end-of-scope
stuff.  You can design any high-quality scheme you want, and for
those cases where an explicit alternative is required, try/finally
(or equivalent) can be used.

I was trying to make your problem simpler, by punting one part
of it to the results of the try/finally effort.  Sorry for the
confusion.

Yours, &c, Tony Olekshy



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: 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: 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



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

2001-02-12 Thread Tony Olekshy
 great discussion about this, with one camp suggesting
that post/finally shouldn't propagate trapped exceptions, because
you can always do it explicitly in every post/finally you write.
Others considered that to be a dangerous proposal, because of how
easy it would be to forget the re-throw in the common case.

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

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



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



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: 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: 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 B&D 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: 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: 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: 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 C, though I would much prefer a
> > more generic name, such as C.
> 
> 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 er

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 C, though I would much prefer a
> more generic name, such as C.

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



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: 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 C 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: 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: 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 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 C attribute.

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

> A C 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 95 (v1) Object Classes

2000-08-12 Thread Tony Olekshy

Andy Wardley wrote:
>
> A key feature of this proposal is that object/class variable and
> methods are indistinguishable to the user.  The dot operator does
> the right thing to call a method (if defined), or instead access a
> variable, or follow a delegation reference, etc. i.e.
>
> $foo.bar
>
> is something like (assuming a blessed hash)
>
> UNIVERSAL::can($foo, 'bar') ? $foo->bar() : $foo->{'bar'};
>
> '->' and '::' won't do that, and shouldn't.  If we tried to overload
> '::' or '->' to be more magical then we would break things all over
> the place.

I don't understand.  Why don't you just have the class generator
automatically create an accessor method for every declared instance
variable and otherwise prevent access to the instance variable
except via said method?  Now methods and ivars look the same because
ivars *are* methods (accessor methods), from the perspective of the
class client.

This also means that if you define visibility constraints for
methods you more-or-less automatically get them for ivars, again
because ivars are only visible via their accessor methods.

That's how that Prothos::Class module I mentioned in a previous
message (about RFC 92) works.

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 (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



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

2000-08-10 Thread Tony Olekshy

Peter Scott wrote:
>
> try {
> } catch Exception::IO with {
> } catch Exception::Socket with {
> } otherwise {
> };

Jonathan Scott Duff wrote:
>
> try {
> } catch {
> switch ($EXCEPTION->name) {
> case IO { ... }
> case Socket { ... }
> }
> }
>
> The catch clause would catch all exceptions.  The one
> thrown would be placed in a "global" $EXCEPTION variable.

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 { ... }
  }
  }

There is no need for a "global".

Let's take this discussion to [EMAIL PROTECTED],
and give it a new subject.

Yours, &c, Tony Olekshy
[EMAIL PROTECTED]