On Fri, Sep 30, 2005 at 17:09:23 +0200, TSa wrote:
> And it is the type system that guaranties the availability
> of the required information e.g. in $!.

$! is polymorphic.

Since CATCH is a topcializer, and you use when blocks to case over
$!, you can check to see if it has the metadata you want yourself:

        CATCH {
                when It::Is::An::Error::I::Can::Deal::With {
                        deal_with_error_of_kind_foo($!); # it may resume
                }
        }

> >Reentrancy is an implementation detail best left unmentioned.
> 
> the reentrance proplem is just there

No, it's not - the solution is that $! is bound lexically to the
CATCH block. Exceptions that redefine $! keep the old value in the
exception stack inside of each exception, but this does not trample
any CATCH block. It'd be outright stupid to make

        CATCH {
                handle_error();
                warn "$! was thrown within the code yadda";
        }

print out completely bogus info becaue handle_error overwrote $!.

We can even deal with this in perl 5:

        eval { bad_code };
        if ($@) {
                {
                        local $@;
                        code_that_might_die_in_a_handler;
                }

                warn "$! was thrown within bad_code";
        }

> Just to synchronize our understanding, I see the following
> equivalences from the data and code domains
> 
>      data    code
> 
>      class = sub
>   instance = invocation

What?

> To illustrate my view consider

didn't help.

> The view I believe Yuval is harboring is the one examplified
> in movies like The Matrix or The 13th Floor and that underlies
> the holodeck of the Enterprise: you can leave the intrinsic
> causality of the running program and inspect it. Usually that
> is called debugging. But this implies the programmer catches
> a breakpoint exception or some such ;)

Err, no.

What I want is for perl 6 to help me write high quality user
interfaces easily.

One aspect of making this easy is letting me bridge between
exception throwing code and the UI layer using continuations.

> Exception handling is the programmatic automatisation of this
> process. As such it works the better the closer it is in time
> and context to the cause and the more information is preserved.

I read that as:

        "As such it works the better the farther it is in time and
        context from the UI code"

and I must disagree, but it is a matter of style.

As for information preserval:

        * every object that inherits Exception can have an arbitrary
        number of attributes.

        * the base class Exception has code to make it be thrown,
        or rethrown cleanly by making the previous value of $! available
        as an attribute of the new value of $!

        * Exception's constructor knows exactly where everything
        happenned (for error reporting, *AND* resuming)

        * a transition into a 'use fatal' lexical scope will cause the
        throw method to be called on a value being returned, if it is an
        exception.

        * if the next statement to be executed is not inside a CATCH
        block, the error object deletes it's .resume continuation, to
        clean up the lexical scope that is still alive inside it. This
        should be optional.

> But we all know that a usefull program is lossy in that respect.
> It re-uses finite resources during its execution. In an extreme
> setting one could run a program *backwards* if all relevant
> events were recorded!

That's a job for omniscient debuggers.

Languages with continuations are not debuggers.

Exceptions are not raised for every opcode, just to record the flow.
Exceptions normally do not happen.

> >Yes, even signals and exceptions.
> >The runtime is responsible for making these as fast as possible
> >without being unsafe.
> 
> Hmm, I would see the type system in that role. It has all the
> information of the interested parties in a longjump. If it knows
> there are no potential handlers

The type system has nothing to do with code reentrency due to an
icky implementation that shares code.

Since malloc cannot be safely called within a C level signal
handler, the runtime needs to be responsible for setting the virtual
machine instruction pointer to the signal handling code, and to
mark a flag, and at the next opcode dispatch (no longer an unsafe
place) the signal handler will really happen.

This has nothing at all to do with the type system, and doesn't even
have anything to do with perl - this is parrot (or whoever)'s job.

> >It can't be a method because it never returns to it's caller - it's
> 
> It beeing the CATCH block?

No, .resume.

I take it back, it could be a method that invokes a continuation.


> metric for dispatch applies. BTW, how is the signature of a CATCH
> block given? Simply

CATCH is just a topicalizer and a trait on the lexical scope.

Within it $! is topicalized, and you use when:

        CATCH {
                when rx/Permission denied/ { }
                when Exception::Class { }
                ...
        }

> >a continuation because it picks up where the exception was thrown,
> 
> I would say it is given information about. In a way an exception
> handler is dispatched on the type of exception.

Again, you're confusing CATCH and .resume. CATCH is just a block of
code that is jumped to when there is an exception. It may be jumped
to because it's a continuation, but this is irrelevant. 

.resume picks up where the exception was thrown - it is the
continuation that is the rest of the code after the 'die' or 'fail'
or whatever.

> This is the thing that I see is hardly possible from a far away scope.
> But fair enough for closely related code.

Since you know what kind of exception it is, you can know how to fix
it. If it's an IO::Open error, the solution is to give back an
alternative handle. If it's a Socket::Connect error the solution is
to find another way to connect to it.

If i'm writing a mail client I may want Socket::Connect to work
entirely different. There I have knowlege about what kind of
connection it is. In fact, I could write Socket::IMAP, which throws
a Socket::IMAP::Connect error, to help my exception handling code
cope better.

The exception handling code could display an error dialog saying
e.g. "Connection refused. Should I try an ssh tunnel instead?", and
if so, it could try to instantiate a Socket::IMAP::Tunneled and
return that instead.

However, Socket::IMAP might be a superclass that doesn't know about
Socket::IMAP::Tunneled, and neither should know about the UI code.

> My view is that a (free) method type becomes a continuation
> as follows:

Do you grok continuations? It doesn't look like it - you seem to
have confused things.

Let me illustrate. A coroutine, for example that has a yield:

        sub foo {
                for 1 .. 2 -> $x {
                        yield $x;
                }

                return "end";
        }
        
        say foo; # 1
        say foo; # 2
        say foo; # "end"
        say foo; # 1
        ...

the way the coroutine works is that when it 'yield's a continuation
for the rest of the call to foo is stored, and the value is
returned.

On the next invocation of 'foo', the continuation is used instead -
the loop picks up right at the end when $x is still 1, and the body
of the loop ends. Then 2 is bound to $x and we yield again. foo is
invoked again and the new continuation is taken - right at the end
of the loop block. The loop has now finished, so we go to the next
statement: return "end". Return does not store a continuationand the
value is returned.

On the next invocation of 'foo', the continuation is used instead -
the loop picks up right at the end when $x is still 1, and the body
of the loop ends. Then 2 is bound to $x and we yield again. foo is
invoked again and the new continuation is taken - right at the end
of the loop block. The loop has now finished, so we go to the next
statement: return "end". Return does not store a continuation - the
next invocation of foo will start all over.

>    7a) a return uses the return continuation in such a way that
>        the invocation is abandoned after the jump
>     b) a yield keeps the continuation just like a constructed object
>        and packages it as some kind of attachment to the return value.
>        BTW, I think there are more data types that use this technique
>        then one might think on first sight. Iteraters, junctions and
>        lazy evaluation in general come to mind.

This is the part that convinced me there was confusion.

A coro macro could work something like this:

        macro coro ($name, $pattern_tuple, &body) {
                Perl6::Sub.new(
                        :name($name),
                        :pattern_tuple($pattern_tuple),
                        body => sub (*$a) {
                                state &coro_continuation;
                                if (defined &coro_continuation) {
                                        return &coro_continuation.();
                                } else {
                                        my &orig_return := &return;
                                        temp our &yield = sub (*$a) {
                                                &coro_continuation := 
&CALLER_CONTINUATION; # the code right after the yield();
                                                orig_return(*$@);
                                        };
                                        temp &return = {
                                                undefine(&coro_continuation);
                                                orig_return(*$@);
                                        }
                                }

                                &body.(*$a);

                                undfine(&coro_continuation);
                        },
                )
        }

-- 
 ()  Yuval Kogman <[EMAIL PROTECTED]> 0xEBD27418  perl hacker &
 /\  kung foo master: /me sushi-spin-kicks : neeyah!!!!!!!!!!!!!!!!!!!!

Attachment: pgpvqWksdvcPb.pgp
Description: PGP signature

Reply via email to