develooper Front page | perl.perl6.language | Postings from February 2001

Re: End-of-scope actions: Toward a hybrid approach.

Thread Previous | Thread Next
From:
Tony Olekshy
Date:
February 14, 2001 18:43
Subject:
Re: End-of-scope actions: Toward a hybrid approach.
Message ID:
3A8B4236.3873EBC3@avrasoft.com
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 { d }

    if ( a ) { b } else { try { c } catch { d } }

    if ( a ) { try { b } catch { c } }
    else     { try { d } catch { e } }

Finally, I'd like to revisit the matter of always.  First consider
the case where always is a dangling block like except.  In such a
case, the following could be written:

    $x = f() always { g($x) };

which would call g if f throws.  With the standalone statement
behaviour, wouldn't I have to write:

    always { g($x) };  $x = f();

If y'all can agree on a set of interpretations similar to a sub-set
of those described above, then I can extend the syntax defined at
http://www.avrasoft.com/perl6/rfc88.htm#Syntax to include except and
always, and completely define the details of their behaviour by
using their try dualities.  I can't extend the reference model past
what I've done, because of the implied try scopes, but we could do
enough with a source code filter to update the RFC 88 regression
tests to cover except and always via their dualities.

That could benefit those of you who prefer using the except and always
constructs, because then they could be understood in terms of the
RFC 88 Perl 5 reference implementation.  If we want to get except and
always into Perl 6, this approach could help provide the details needed
to complete http://tmtowtdi.perl.org/rfc/119.html#IMPLEMENTATION.  Also,
for those who prefer the try/catch/finally approach, if we can establish
these dualities then (1) they can do it their way, and (2) we can do it
both ways (when circumstances make such a elocution clearer, rather
than obfuscating it).

Don't forget, we're building the basis for Perl 6's future idiomatic
forms (especially if the core signals "failures" via exceptions).
Let's give ourselves some room to work, shall we ;-?

Yours, &c, Tony Olekshy

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About