Re: Exceptuations

2005-10-06 Thread Yuval Kogman
On Wed, Oct 05, 2005 at 13:00:55 -0600, Luke Palmer wrote:

 I don't think it was a how is this possible, but more of a what
 business does it have?.  And as far as I gathered, they're saying
 pretty much what you've been saying, but in a different way.  It's
 about the continuation boundary; that is, if you're outside a module,
 you have no say in how the module does its business.  You can continue
 only at the module boundary, replacing a return value from its public
 interface.

As I see it this is the usefulness of exceptions being handled by
distant code.

The code in the module inverts it's interface by calling code it
doesn't know with a certain parameter, accepting a certain parameter
back.

That way encapsulation is not broken, but errors that happen deep
inside a call chain can be dealt with by code that can interact with
the user.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me climbs a brick wall with his fingers: neeyah!



pgpmp8WUodYYB.pgp
Description: PGP signature


Re: Exceptuations

2005-10-06 Thread Yuval Kogman
On Wed, Oct 05, 2005 at 13:41:37 -0700, Dave Whipp wrote:
 Reading this thread, I find myself wondering how a resumable exception 
 differs 
 from a dynamically scropted function. Imagine this code:

This is sort of like what I mean, except that there is no
encapsulation breakage, since the interface is inverted.

The advantage of this approach is that error handling code in a
submodule can benefit from generic, reusable exception handling code
that is provided by it's caller.

temp sub FileNotWriteable( Str $filename ) {

With an exception handler and continuable exceptions you don't have
to know what the error handler is, or make sure that the module
actually throws the error.

The exception handler instead deals with the type of the exception
in a generic manner (it doesn't care when the exception was actually
generated).

The module doesn't need to throw the error it just needs to fail (or
delegate a fail), until the failure crosses into a 'use fatal'
scope.

That way both the catching code and the throwing code are reusable
and orthogonal when they are unrelated, but the possibility of
coupling handling code with throwing code is still there.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me groks YAML like the grasshopper: neeyah!!



pgpzo38NCmZ47.pgp
Description: PGP signature


Re: zip: stop when and where?

2005-10-06 Thread Luke Palmer
On 10/5/05, Damian Conway [EMAIL PROTECTED] wrote:
 Luke wrote:
   I'm just wondering why you feel that we need to be so careful.

 Because I can think of at least three reasonable and useful default behaviours
 for zipping lists of differing lengths:

  # Minimal (stop at first exhausted list)...
  for @names ¥ @addresses - $name, $addr {
  ...
  }


  # Maximal (insert undefs for exhausted lists)...
  for @finishers ¥ (10..1 :by(-1))  - $name, $score {
  $score err next;
  ...
  }


  # Congealed (ignore exhausted lists)...
  for @queue1 ¥ @queue2 - $server {
  ...
  }

 Which means that there will be people who expect each of those to *be* the
 default behaviour for unbalanced lists.

Perhaps that makes sense.  That certainly makes sense for other kinds
of constructs.  Something makes me think that this is a little
different.  Whenever somebody asks what Y is on #perl6, and I tell
them that it interleaves two lists, a follow-up question is *always*
what does it do when the lists are unbalanced.  Now, that may just
be a behavior of #perl6ers, but I'm extrapolating.  It means that
there isn't an assumption, and if they weren't #perl6ers, they'd RTFM
about it.

When I learned Haskell and saw zip, I asked the very same question[1].
 I was about as comfortable writing Haskell at that point as beginning
programmers are with writing Perl, but it still took me about ten
seconds to write a test program to find out.  The rest of Perl doesn't
trade a reasonable default behavior for an error, even if it *might*
be surprising the first time you use it.  It doesn't take people long
to discover that kind of error and never make that mistake again.

If we make zip return a list of tuples rather than an interleaved
list, we could eliminate the final 1/3 of those errors above using the
typechecker.  That would make the for look like this:

for @a Y @b - ($a, $b) {...}

An important property of that is the well-typedness of the construct. 
With the current zip semantics:

my A @a;
my B @b;
for @a Y @b - $a, $b {
# $a has type A (+) B
# $b has type A (+) B
}

With tuple:

my A @a;
my B @b;
for @a Y @b - ($a, $b) {
# $a has type A
# $b has type B
}

Which is more correct.  No... it's just correct, no superlative
needed.  It also keeps things like this from happening:

for @a Y @b - $a, $b {
say $a ; $b
}
# a1 b1
# a2 b2
# a3 b3
# ...

Oh, I need a count, says the user:

for @a Y @b Y 0... - $a, $b {  # oops, forgot to add $index
say $a ; $b
}
# a1 b1
# 0  a2
# b2 1
# ...

Luke

[1] But I didn't need to.  The signature told me everything:

zip :: [a] - [b] - [(a,b)]

It *has* to stop at the shortest one, because it has no idea how to
create a b unless I tell it one.  If it took the longest, the
signature would have looked like:

zip :: [a] - [b] - [(Maybe a, Maybe b)]

Anyway, that's just more of the usual Haskell praise.


Re: zip: stop when and where?

2005-10-06 Thread Dave Whipp

Luke Palmer wrote:


zip :: [a] - [b] - [(a,b)]

It *has* to stop at the shortest one, because it has no idea how to
create a b unless I tell it one.  If it took the longest, the
signature would have looked like:

zip :: [a] - [b] - [(Maybe a, Maybe b)]

Anyway, that's just more of the usual Haskell praise.


Given that my idea about using optional binding for look-ahead didn't 
fly, maybe it would work here, instead:


  @a Y @b -  $a,  $b { ... } # stop at end of shortest
  @a Y @b -  $a, ?$b { ... } # keep going until @a is exhaused
  @a Y @b - ?$a, ?$b { ... } # keep going until both are exhaused

I think we still need a way to determine if an optional arg is bound. 
Can the Cexists function be used for that (if exists $b {...})?



Dave.


Re: Exceptuations

2005-10-06 Thread Peter Haworth
On Wed, 5 Oct 2005 19:24:47 +0200, Yuval Kogman wrote:
 On Wed, Oct 05, 2005 at 16:57:51 +0100, Peter Haworth wrote:
  On Mon, 26 Sep 2005 20:17:05 +0200, TSa wrote:
   Piers Cawley wrote:
   Exactly which exception is continued?
The bottommost one. If you want to return to somewhere up its call
chain, do:
   
  $!.caller(n).continue(42)
  
   Whow, how does a higher level exception catcher *in general* know
   what type it should return and how to construct it? The innocent
   foo() caller shouldn't bother about a quux() somewhere down the line
   of command. Much less of its innards.
  
  Well said.
 
 No! Not well said at all!

Sorry, I misread that. I thought I was agreeng with how does a higher
level exception catcher know what to change in order to make resuming the
continuation useful?, especially in the light of Piers saying that the
bottom-most exception should be the one resumed.

The highest level exception is the only one a caller has any right to deal
with, but even then it doesn't really know what will happen if it resumes
some random continuation attached to the exception.

   CATCH {
   when some_kind_of_error {
   $!.continue($appropriate_value_for_some_kind_of_error)
   }
   }

That just gives me the willies, I'm afraid.

-- 
Peter Haworth   [EMAIL PROTECTED]
Disconcerting Haworth Fortress Unicycling Melody Gundam
-- http://www.channel4.com/4later/bits/manga.html


Re: zip: stop when and where?

2005-10-06 Thread Jonathan Scott Duff
On Thu, Oct 06, 2005 at 10:31:50AM -0600, Luke Palmer wrote:
 If we make zip return a list of tuples rather than an interleaved
 list, we could eliminate the final 1/3 of those errors above using the
 typechecker.  That would make the for look like this:
 
 for @a Y @b - ($a, $b) {...}

I like it (I think). I'm not sure about the syntax though. Is this one
of those places where round brackets are equivalent to square brackets?
I.e., would this be the same:

for @a ¥ @b - [$a,$b] { ... }

?

Also, it seems like this syntax would almost always require the brackets
to be correct. Most of the time people will see and expect for loops
that look like this:

for MUMBLE - $a, $b { ... }

Except now they've probably got a semantic error when MUMBLE contains ¥
or is prefixed by zip. This type of error mayn't be so easy to detect
depending on what they're mumbling about.

-Scott
-- 
Jonathan Scott Duff
[EMAIL PROTECTED]


Re: zip: stop when and where?

2005-10-06 Thread Juerd
Dave Whipp skribis 2005-10-06  9:57 (-0700):
 Given that my idea about using optional binding for look-ahead didn't 
 fly, maybe it would work here, instead:
   @a Y @b -  $a,  $b { ... } # stop at end of shortest
   @a Y @b -  $a, ?$b { ... } # keep going until @a is exhaused
   @a Y @b - ?$a, ?$b { ... } # keep going until both are exhaused
 I think we still need a way to determine if an optional arg is bound. 
 Can the Cexists function be used for that (if exists $b {...})?

Y isn't something that is specific to for loops, or to sub invocation,
so this cannot be a solution.

Also remember that Y creates a single flattened list by definition, and
that the given sub's arity determines how many items of that list are
used.

It's perfectly legal and possibly even useful to say

for @foo, @bar, @baz - $quux, $xyzzy { ... }

And even though

for @foo Y @bar Y @baz - $quux, $xyzzy { ... }

is something you will probably not see very often, it's still legal
Perl, even though it looks asymmetric. This too makes finding the
solution in arguments a non-solution.


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html


Re: zip: stop when and where?

2005-10-06 Thread Luke Palmer
On 10/6/05, Juerd [EMAIL PROTECTED] wrote:
 for @foo Y @bar Y @baz - $quux, $xyzzy { ... }

 is something you will probably not see very often, it's still legal
 Perl, even though it looks asymmetric. This too makes finding the
 solution in arguments a non-solution.

Don't be silly.  There's no reason we can't break that; it's not an
idiom anybody is counting on.  If you still want the behavior:

for flatten(@foo Y @bar Y @baz) - $quux, $xyzzy {...}

But your point about Y returning a list and therefore not being
for-specific is quite valid.

Luke


$value but lexically ...

2005-10-06 Thread Dave Whipp
Cbut properties get attached to a value, and are available when the 
value is passed to other functions/ etc. I would like to be able to 
define a property of a value that is trapped in the lexical scope where 
it is defined. The example that set me thinking down this path is


sub foo( $a, ?$b = rand but :is_default )
{
   ...
   bar($a,$b);
}

sub bar( $a, ?$b = rand but :is_default )
{
  warn defaulting \$b = $b if $b.is_default;
  ...
}


It would be unfortunate if the is_default property attached in foo 
triggers the warning in bar. So I'd like to say somthing like


  sub foo( $a, ?$b = 0 but lexically :is_default ) {...}
or
  sub foo( $a, ?$b = 0 but locally :is_default ) {...}

to specify that I don't want the property to the propagated.


Re: Exceptuations

2005-10-06 Thread Yuval Kogman
On Thu, Oct 06, 2005 at 18:11:38 +0100, Peter Haworth wrote:

 The highest level exception is the only one a caller has any right to deal
 with, but even then it doesn't really know what will happen if it resumes
 some random continuation attached to the exception.

But then we gain nothing

  CATCH {
  when some_kind_of_error {
  $!.continue($appropriate_value_for_some_kind_of_error)
  }
  }
 
 That just gives me the willies, I'm afraid.

Why?

when i can't open a file and $! tells me why i couldn't open, i
can resume with an alternative handle that is supposed to be the
same

when I can't reach a host I ask a user if they want to wait any
longer

when disk is full I ask the user if they want to write somewhere
else

when a file is unreadable i give the user the option to skip

These handlers are progressively more knowlegable of the code
they're dealing with, but they don't touch the actual guts - that's
the whole merit of continuable exception, because otherwise you
might aswell just start over.

These are 100% reusable in the first exception handler, and not
reusable but still applicable to an opaque call at the last handler.
It doesn't matter who opens the file file, the exception handler
will produce the same effect but in a different way.

CATCH {
when Error::IO::... {
open ...
}

when MyApp::Timeout {
ask_user_to_continue_or_abort();
}
...
}

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me dodges cabbages like macalypse log N: neeyah!



pgpQfW4BcQBM2.pgp
Description: PGP signature


Re: $value but lexically ...

2005-10-06 Thread Luke Palmer
On 10/6/05, Dave Whipp [EMAIL PROTECTED] wrote:
 sub foo( $a, ?$b = rand but :is_default )
 {
 ...
 bar($a,$b);
 }

 sub bar( $a, ?$b = rand but :is_default )
 {
warn defaulting \$b = $b if $b.is_default;
...
 }


 It would be unfortunate if the is_default property attached in foo
 triggers the warning in bar. So I'd like to say somthing like

sub foo( $a, ?$b = 0 but lexically :is_default ) {...}
 or
sub foo( $a, ?$b = 0 but locally :is_default ) {...}

 to specify that I don't want the property to the propagated.

This came up before when I proposed lexical properties.  That was
before we knew that a property was just a role.  So you can do a
lexical property like so:

{
my role is_default {}   # empty
sub foo($a, ?$b = 0 but is_default) {...}
}
{
my role is_default {}
sub bar($a, ?$b = rand but is_default) {...}
}

If this turns out to be a common want, I can see:

sub bar($a, ?$b = rand but my $is_default) {
warn Defaulted to $b if $b.does($is_default);
}

But I don't think it will be, and the empty role is easy enough.

Luke


Re: Exceptuations

2005-10-06 Thread Luke Palmer
On 10/6/05, Yuval Kogman [EMAIL PROTECTED] wrote:
 when i can't open a file and $! tells me why i couldn't open, i
 can resume with an alternative handle that is supposed to be the
 same

 when I can't reach a host I ask a user if they want to wait any
 longer

 when disk is full I ask the user if they want to write somewhere
 else

 when a file is unreadable i give the user the option to skip

I'm not bashing your idea, because I think it has uses.  But I'll
point out that all of these can be easily accompilshed by writing a
wrapper for open().  That would be the usual way to abstract this kind
of thing.

Luke


Re: $value but lexically ...

2005-10-06 Thread Juerd
Luke Palmer skribis 2005-10-06 14:23 (-0600):
 my role is_default {}   # empty
 sub foo($a, ?$b = 0 but is_default) {...}

Would this work too?

0 but role {}


Juerd
-- 
http://convolution.nl/maak_juerd_blij.html
http://convolution.nl/make_juerd_happy.html 
http://convolution.nl/gajigu_juerd_n.html


Re: $value but lexically ...

2005-10-06 Thread Luke Palmer
On 10/6/05, Juerd [EMAIL PROTECTED] wrote:
 Luke Palmer skribis 2005-10-06 14:23 (-0600):
  my role is_default {}   # empty
  sub foo($a, ?$b = 0 but is_default) {...}

 Would this work too?

 0 but role {}

Most certainly, but you would have no way to refer to that role later,
so it is questionable how useful that construct is.  No, it's not
questionable.  That is a useless construct.

Luke


Type annotations

2005-10-06 Thread Luke Palmer
Autrijus convinced me that we have to really nail down the semantics
of type annotation without use static.   Let's first nail down what
I meant by semantics in that sentence.  Basically, when do various
things get checked?  Run time or compile time (not coercion; I have a
proposal for that coming).

Oh, I'm asking p6l here, not Larry in particular.  This part of the
language is yet-undesigned, so some arguments one way or the other
would be nice to hear.

So we're in line one of a Perl program, with static typing/inference
disabled (or at least inference *checking* disabled; perl may still
use it for optimization).  When do the following die: compile time
(which includes CHECK time), run time, or never?

my Array $a = 97;  # dies eventually, but when?
my Int   $b = 3.1415;  # dies at all?

sub foo (Int $arg) {...}
foo(hello);  # should die at the latest when foo() is called

sub bar (Int $arg -- Str) {...}
foo(bar(42));

sub static  (Code $code, Array $elems -- Array) {
[ $elems.map:{ $code($_) } ]
}
sub dynamic ($code, $elems) {
[ $elems.map:{ $code($_) } ]
}
static({ $_+1 }, dynamic(notcode, [1,2,3,4,5]));
dynamic(notcode, static({ $_+1 }, [1,2,3,4,5]));

That should cover most of the interesting cases.

Luke


Re: Type annotations

2005-10-06 Thread Yuval Kogman
On Thu, Oct 06, 2005 at 17:44:10 -0600, Luke Palmer wrote:
 Autrijus convinced me that we have to really nail down the semantics
 of type annotation without use static.   Let's first nail down what
 I meant by semantics in that sentence.  Basically, when do various
 things get checked?  Run time or compile time (not coercion; I have a
 proposal for that coming).
 
 Oh, I'm asking p6l here, not Larry in particular.  This part of the
 language is yet-undesigned, so some arguments one way or the other
 would be nice to hear.
 
 So we're in line one of a Perl program, with static typing/inference
 disabled (or at least inference *checking* disabled; perl may still
 use it for optimization).  When do the following die: compile time
 (which includes CHECK time), run time, or never?
 
 my Array $a = 97;  # dies eventually, but when?
 my Int   $b = 3.1415;  # dies at all?

Both die at compile time, because the user explicitly contradicted
him/herself. This is like saying

my int = $x :: float;

since they're constants and their types are very well known.

 sub foo (Int $arg) {...}
 foo(hello);  # should die at the latest when foo() is called

Immediately, at compile time, for every caller of foo unless 'no
static' or whatever is active for that scope.

However, no inferencing is made - this is just 1 level deep.

 sub bar (Int $arg -- Str) {...}
 foo(bar(42));

Since -- is explicit I'm not sure if it means infer this even if
we're not globally inferring.

I lean towards compile time error here since I think it would be
nice to have that, but there are some disadvantages.

Perhaps this should infer only in the lexical scope that 'sub bar'
was defined in, to make sure that error reporting does not confuse
naive users of the module that defines foo, without asking for
compile time inference.

 sub static  (Code $code, Array $elems -- Array) {
 [ $elems.map:{ $code($_) } ]
 }
 sub dynamic ($code, $elems) {
 [ $elems.map:{ $code($_) } ]
 }
 static({ $_+1 }, dynamic(notcode, [1,2,3,4,5]));
 dynamic(notcode, static({ $_+1 }, [1,2,3,4,5]));

This is only with full inferencing, either lexically enabled as a a
pragma (in the scope that invokes), or if enabled globally.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me does a karate-chop-flip: neeyah!!



pgpZ0kQYyANwT.pgp
Description: PGP signature


Re: Exceptuations

2005-10-06 Thread Yuval Kogman
On Thu, Oct 06, 2005 at 14:27:30 -0600, Luke Palmer wrote:
 On 10/6/05, Yuval Kogman [EMAIL PROTECTED] wrote:
  when i can't open a file and $! tells me why i couldn't open, i
  can resume with an alternative handle that is supposed to be the
  same
 
  when I can't reach a host I ask a user if they want to wait any
  longer
 
  when disk is full I ask the user if they want to write somewhere
  else
 
  when a file is unreadable i give the user the option to skip
 
 I'm not bashing your idea, because I think it has uses.  But I'll
 point out that all of these can be easily accompilshed by writing a
 wrapper for open().  That would be the usual way to abstract this kind
 of thing.

Stylistically I would tend to disagree, actually. I think it's
cleaner to use exception handling for this.

Also, this implies that you know that the errors are generated by
open. This is OK for open(), but if the errors are generated from a
number of variants (MyApp::Timeout could come from anywhere in a
moderately sized MyApp), then wrapping is not really an option.

-- 
 ()  Yuval Kogman [EMAIL PROTECTED] 0xEBD27418  perl hacker 
 /\  kung foo master: /me groks YAML like the grasshopper: neeyah!!



pgppFkb4LL0f1.pgp
Description: PGP signature


Re: Type annotations

2005-10-06 Thread Ashley Winters
On 10/6/05, Luke Palmer [EMAIL PROTECTED] wrote:
 So we're in line one of a Perl program, with static typing/inference
 disabled (or at least inference *checking* disabled; perl may still
 use it for optimization).  When do the following die: compile time
 (which includes CHECK time), run time, or never?

This is just my opinions as a Perl programmer in the trenches. I would
expect Typed variables to auto-coerce themselves, but not impose
fatality. Predictable auto-coercion would be nifty in quick-and-dirty
programs.

Ignore my advice at will -- nobody's required to use Types in their
own code, so there's no need for them to be universally valuable.

However, since I expect builtins and all standard functions to have
fully declared Type signatures, consider how these decisions would
affect _every_ program, before ordering the summary execution of
everyone's poor little Perl script.

 my Array $a = 97;  # dies eventually, but when?

Runtime -- cannot coerce Int value to Array

 my Int   $b = 3.1415;  # dies at all?

Doesn't die, $b == 3. Int scalars should coerce anything which can be
prefix:+'d.

 sub foo (Int $arg) {...}
 foo(hello);  # should die at the latest when foo() is called

$arg should be undef but Exception::InvalidInteger(Str value 'hello'
cannot be coerced to an Int at $?LINE)

 sub bar (Int $arg -- Str) {...}
 foo(bar(42));

If bar returns a Str ~~ /Perl6::Grammar::Int/, it gets coerced;
otherwise, undef but Exception

 sub static  (Code $code, Array $elems -- Array) {
 [ $elems.map:{ $code($_) } ]
 }
 sub dynamic ($code, $elems) {
 [ $elems.map:{ $code($_) } ]
 }
 static({ $_+1 }, dynamic(notcode, [1,2,3,4,5]));

die Str value 'notcode' cannot be called as a Sub reference -- have
you asked Larry how to make a symbolic function call, lately?;

 dynamic(notcode, static({ $_+1 }, [1,2,3,4,5]));

Same.

Just my 2¢

Ashley Winters


Re: Exceptuations

2005-10-06 Thread Piers Cawley
Peter Haworth [EMAIL PROTECTED] writes:

 On Wed, 5 Oct 2005 19:24:47 +0200, Yuval Kogman wrote:
 On Wed, Oct 05, 2005 at 16:57:51 +0100, Peter Haworth wrote:
  On Mon, 26 Sep 2005 20:17:05 +0200, TSa wrote:
   Piers Cawley wrote:
   Exactly which exception is continued?
The bottommost one. If you want to return to somewhere up its call
chain, do:
   
  $!.caller(n).continue(42)
  
   Whow, how does a higher level exception catcher *in general* know
   what type it should return and how to construct it? The innocent
   foo() caller shouldn't bother about a quux() somewhere down the line
   of command. Much less of its innards.
  
  Well said.
 
 No! Not well said at all!

 Sorry, I misread that. I thought I was agreeng with how does a higher
 level exception catcher know what to change in order to make resuming the
 continuation useful?, especially in the light of Piers saying that the
 bottom-most exception should be the one resumed.

I'm sorry, we appear to have lost some kind of context, the original example
given only had one exception thrown, but it got propagated up through a long
call chain. At no point did anything catch the original exception and
rethrow. If they had, you're absolutely correct in asserting that by default
things should resume from the point of the outermost rethrow. A brave exception
catcher (or more likely programmer with a debugger) might want to crack that
exception open and examine its inner exceptions, but in general that's not
going to be safe.

The scary syntax proposed above is, again, the sort of thing that might be
useful in a debugger I don't really care about the inner workings of these
helper functions, I just want 'open' to return this mocked handle. (actually
in that case, being able to do $!.caller(open).continue(MockIO.new), where
'caller open' looks up the call chain for the lowest call to open and returns
that continuation would be rather neat)

 The highest level exception is the only one a caller has any right to deal
 with, but even then it doesn't really know what will happen if it resumes
 some random continuation attached to the exception.

Oh stop with the 'rights'. And it's not dealing with a 'random' continuation,
if it's going to resume it should be damned careful about which exceptions it
resumes from; you don't just go around doing CATCH {...; $!.continue(...)}, you
do CATCH SomeSpecificKindOfResumableException { ...; $!.continue(...)}. And, in
general, you don't do that either, because in the average program you catch the
exception at a point where you can simply return a sensible default to your
caller. Resumable exceptions come into their own, however, when you're
debugging. I can envisage doing:

  perl6 -debug::on::error some_script

And have it run along happily until an exception gets propagated up to the top
level, at which point the debugger swings into action and uses the continuation
to tunnel back to the point at which the exception was thrown so the programmer
can inspect the program state, possibly fix things up, return something
sensible and carry on.

  CATCH {
  when some_kind_of_error {
  $!.continue($appropriate_value_for_some_kind_of_error)
  }
  }

 That just gives me the willies, I'm afraid.

It doesn't amuse me that much, unless whatever generates
$appropriate_value_for_some_kind_of_error is very, very smart indeed. But, as
I've said above, that's not really where resumable exceptions shine.

-- 
Piers Cawley [EMAIL PROTECTED]
http://www.bofh.org.uk/