On Sat, Oct 01, 2005 at 05:57:54 -0400, Austin Hastings wrote:

> Internally, it may be the same. But with exceptions, it's implemented by
> someone other than the victim, and leveraged by all. That's the kind of
> abstraction I'm looking for. My problem with the whole notion of "Either
> errorMessage resultingValue" in Haskell is that we _could_ implement it
> in perl as "Exception|Somevalue" in millions of p6 function signatures.
> But I don't _want_ to. I want to say "MyClass" and have the IO subsystem
> throw the exception right over my head to the top-level caller.

In haskell it's the job of the Either monad to let you pretend you
aren't doing Exception|Somevalue everywhere.

You can sequence operations in a deeply nested manner, and then
'fail' at some point. Then control flow will just pop back up all
the way with the error, instead of trying to continue.

You don't really need to say 'Either ... ...', you just use do
notation.

> For appropriate definitions of both 'elegant' and 'convenient'. Java
> calls this 'checked exceptions', and promises to remind you when you
> forgot to type "throws Exception::Math::DivisionByZero" in one of a
> hundred places. I call it using a word to mean its own opposite: having
> been exposed to roles and aspects, having to code for the same things in
> many different places no longer strikes me as elegant or convenient.

I agree with that wholeheartedly, but in haskell you are making no
obligation towards the shape of an exception - it can be 'Either
thing Error' where Error is any data type you like.

In this sense haskell is just as flexible but requires more
abstraction than perl etc. It has it's merits - it's safer, and more
reusable. It tends to win ICFP contests, and so forth.

However, to just get that thing working real fast, without having
to pay too much when the context becomes maintenance instead of
development, i think Perl 6 will be the most suitable language in
the world.

> Right. At some level, you're going to have to do that. This to me is
> where the "err" suggestion fits the most comfortably: "err" (or "doh!"
> :) is a keyword aimed at ad-hoc fixes to problems. It smooths away the
> horrid boilerplate needed for using exceptions on a specific basis.

Which is why it's such a nice propsal =)

> As syntactic sugar goes, it's not powerful enough yet.

        err next # catch all
        err Pattern, next # catch some

Putting my code where my mouth is:

        sub infix:<err> (&lhs is delayed, Pattern ?$match = Any, &rhs is 
delayed) {
                lhs;
                CATCH {
                        when $match { rhs }
                        default { die }
                }
        }

Ofcourse, these can also stack:

        my $fh = open "file
                err rx/Permission Denied/, next
                err rx/No such file/, die;

But i don't think this is very useful for one or at the very most
two catches - for anything else it's ad-hoc nature just doesn't
scale as nicely as CATCH blocks, which can be applied to several
error generating blocks of code at once.

Ofcourse, true acid heads can always say:

        do {
                ...;
                ...;
        } err ..., ...
          err ..., ...;

but that's their problem. =)

> The last sentence is telling, I think. The run-time system SHOULD take
> as much care as possible. And rub my feet.

Yes =)

> True for any method that invokes exit(), no? Or that says NEXT on a
> label outside its scope.

Well, that's a semantic detail. The issue is that those methods
*can* return, but don't.

A continuation will never return - because it already has another
place to return - the place that created it.

This is ignoring CPS, ofcourse, in which every return and every call
is a continuation. While this may be true under the hood, this is
not what the average Perl 6 user can observe.

> The scenario is that I try something (error_throwing_code) and catch an
> exception. Then while showing a dialog box to the user, for example, I
> get another exception: not enough handles or whatever. So someone higher
> than me resolves that on my behalf, then resumes me. I'm still trying to
> resume the error thrown earlier:

Yes, that should work.

> Now I need to ask, what happens when show_dialog_box throws an
> exception? Presumably, I don't catch it in this code path, or there will
> be a stack fault shortly.

If the exception from show_dialog_box was thrown, and another CATCH
handler fixed it for you, you don't need to worry about it - you can
never know because you don't get access to that exception. It's as
if it was never propagated.

> One possibility is that the catcher of an exception knows little or
> nothing about the innards of the thrower.

It's the job of exception classes to bridge these - they have a
class, and any number of attributes.

        Exception::IO::Open::PermissionDenied

In fact I suspect that Exception::IO::Open enforces a certain type of
fix, too:

        class Exception::IO::Open is Exception {
                has $.path; # what we tried to open
                has $.code; # the OS error code
                has $.mode; # the mode we attempted to open it with

                ...
        
                method resume (IO::Handle $thing) {
                        $?SELF.SUPER::resume($thing);
                }
        }


That way any bit of code that does:

        CATCH {
                when Exception::IO::Open {
                        ..
                }
        }

has documented, encapsulation safe tools to fix IO related errors,
by redoing the call to open after remedying the situation.

It doesn't need to know what code actually called open().

Nowadays to get "standard" behavior from a UI toolkit would you have
to break abstraction and say 

        My::Toolkit::open(...);

to get semantics like a standard administrative access panel.

With continuable exceptions you just use plain open, and the UI code
can wrap your entire app with a rich standard library of exception
handlers.

> {
>   error_throwing_code();
>   CATCH {
>     show_dialog_box();
>     CATCH {
>       throw;   # Pass the exception
>       show_dialog_box(); # Retry if I get resumed?
>     }
>   }
> }
> 
> That's going to get old, quickly.

Just

{
        error_throwing_code();
        CATCH {
                show_dialog_box();
        }
}

since the parent CATCH will resume from *inside* show_dialog_box.

The abstraction of continuable exceptions should cascade.

> But <c>resume</c> should be part of the Exception interface.

Aye, see usefulness of this in above example.

> >resuming. This is nice because especially if we're trying to e.g.
> >
> >     my @handles = map { open $_ } @file_names;
> >
> >we can let the user skip unreadable files, by using return with no
> >value instead of returning a handle. This is a generic pattern that
> >enhances the user experience by not forcing the user to start over
> >again.
> >
> >For more specific code, i doubt there will be several exceptions of
> >the same kind in a call chain.
> >  
> >
> What's your example there? The "err undef" fashion, or the "pops up a
> dialog box and then calls setuid()"?

An exception ahndler that pops up a dialog box.

In this case it would be:

        The file <x> could not be read: $!

        chmod it (chmod the file, and reopen it with same args)

        skip it (resume with no value)

        abort the program (rethrow instead of resume)

Now, if the chmod operation had an exception like permission denied,
obviously we are not the owner. To chown the file we need to setuid,
and for that we need the user to authenticate.

> I confess I find that (the dialog box) an amazing piece of work, but in
> practical terms somebody someplace has to be doing a retry: I don't see
> how it would work via resuming an exception.

That's the point of continuable exceptions. When returning an
exception from 'open' which is then thrown due to 'use fatal', the
exception handler can then resume from the point where it was
thrown, effectively replacing the exception object with a handle,
that is then assigned to the variable:

        my $handle = open "file";

Under 'no fatal' $handle will have an exception object

under 'use fatal' $handle will not be set at all... Unless the
exception handler provides a different value to be put into $handle.

> Unless Damian does it ;)

I doubt even Damian likes to have all the lexical scopes his program
made boo-boos in stay alive with no GC in case someone at some later
point in the program decides that they can fix those errors.

Also - after the code happenned, certain blocks of code will be
repeated.

This might be useful for obfuscation though ;-)

> My suggestion here is that <c>with</c> load the dataspace of the
> continuation atop the current environment.

Yes, I see, but instead of doing it that way you can do it more
safely with more characters by introspecting the exception object
and using well documented attributes instead.

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

Attachment: pgpzGrZgxcF7q.pgp
Description: PGP signature

Reply via email to