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.

> Think of receiving a 'shelf picker died of lung cancer' exception
> when you just ordered a book from your favorite book dealer.
> Irrespective of the seriousness to the shelf picker, but how would
> you expect a customer to handle such an exception?

This kind of exception should never get so far up the call chain,
except possibly as a nested cause of a more general exception. The
customer is in no position to get the book dealer to choose a
different stock picker - that's up to the order picking department of
the book shop. If it doesn't get handled there, then maybe the book
shop can try sourcing the book externally, and if that fails, they may
defer your order until later. The shop could ask the customer's
opinion as to the suitability of each of these options, but the
customer shouldn't have to know how the shop is implemented and make
such decision unprompted.

Even given a continuation to some low level routine, anything the
caller does is likely to be too far removed to make it sensible to
resume the continuation.

Eiffel deals with this by brutally its Design By Contract magic
bullet: Since all the code catching the exception knows about is its
own implementation, the only sane option it has is to try performing
the subtask in a different way. Here's how Eiffel's rescue/retry might
work in perl6, where "rescue" is spelled "CATCH".

  class Picker{
    # An individual order picker can pick a book, but may unfortunately
    #   die of lung cancer, or just fail to find the book
    method pick($book){
      fail Err::LungCancer if .is_smoker();
      fail Err::BookNotFound if ...;

  class PickingDept{
    # The picking department employs pickers to pick books
    # If an employee dies of lung cancer while picking an order,
    #   they are removed from the roster, and a different picker is chosen
    # If the department doesn't have enough free pickers,
    #   it just throws a "too busy" exception
    # Due to the retry semantics, the department will keep choosing pickers
    #   until one of them can pick the book, or they all die of lung cancer,
    #   (or they're all busy doing something else)
    method pick($book){
      my $picker=.find_free_picker();

        when Err::NoPickersAvailable { fail Err::DeptTooBusy; }
        when Err::LungCancer {
          .fire_picker($picker); # Harsh, but we won't find him again
          retry; # This re-runs the tried block (method) from the top
        when Err::BookNotFound { fail Err::OutOfStock; } # Optimistic, maybe
        default { fail; }

  class BookStore{
    # The book store has multiple picking departments, so if one of them fails
    # to find a book, the others can be tried. If that fails, they could order
    # the book from the wholesaler and defer the order, but I'm too lazy
    method order($book){
      for @.depts -> $dept {
          CATCH{ 1; } # We'll just try the next one
      fail Err::BookNotFound;


  class Customer{
    # The customer doesn't have any say in how bookshops are run, so all
    # they can do if their order is refused, all they can do is try another
    # shop, or give up and go home
    method buy_book($book){

      CATCH{ fail Err::BookObviouslyDoesntExist; }

        Peter Haworth   [EMAIL PROTECTED]
Hestons' First Law: I qualify virtually everything I say.

Reply via email to