Re: Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-10-01 Thread Austin Hastings
Yuval Kogman wrote:

On Thu, Sep 29, 2005 at 13:52:54 -0400, Austin Hastings wrote:
  

[Bunches of stuff elided.]

A million years ago, $Larry pointed out that when we were able to use
'is just a' classifications on P6 concepts, it indicated that we were
making good forward progress. In that vein, let me propose that:

* Exception handling, and the whole try/catch thing, IS JUST An awkward
implementation of (late! binding) run-time return-type MMD.



Exception handling is just continuation passing style with sugar.

Have a look at haskell's either monad. It has two familiar keywords
- return and fail.
  

Every statement in a monadic action in haskell is sequenced by using
the monadic bind operator.

The implementation of =, the monadic bind operator, on the Either
type is one that first check to see if the left statement has
failed. If it does, it returns it. If it doesn't it returns the
evaluation of the right hand statement.

Essentially this is the same thing, just formalized into a type  


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.

I guess that to me, exceptions are like aspects in they should be
handled orthogonally. Haskell's Either doesn't do that -- it encodes a
union return type, and forces the call chain to morph whenever
alternatives are added. The logical conclusion to that is that all subs
return Either Exception or Value, so all types should be implicitly
Either Exception or {your text here}. If that's so, then it's a
language feature and we're right back at the top of this thread.

Specifically, if I promise you:

  sub foo() will return Dog;

and later on I actually wind up giving you:

  sub foo() will return Exception::Math::DivisionByZero;



In haskell:

   foo :: Either Dog Exception::Math::DivisionByZero

e.g., it can return either the expected type, or the parameter.

Haskell is elegant in that it compromises nothing for soundness, to
respect referential integrity and purity, but it still makes thing
convenient for the programmer using things such as monads

  


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.

the try/catch paradigm essentially says:

I wanted to call csub Dog foo()/c but there may be times when I
discover, after making the call, that I really needed to call an anonymous
csub { $inner::= sub Exception foo(); $e = $inner(); given $e {...} }/c.



Yes and no.

The try/catch mechanism is not like the haskell way, since it is
purposefully ad-hoc. It serves to fix a case by case basis of out
of bounds values. Haskell forbids out of bound values, but in most
programming languages we have them to make things simpler for the
maintenance programmer.
  


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.

  do_something() err fix_problem();

is much easier to read than the current

 { do_something(); CATCH { fix_problem(); }}

by a lot. But only in two conditions: first that all exceptions are
identical, and second that the correct response is to suppress the
exception.

To me that fails because it's like Candy Corn: you only buy it at
Halloween, and then only to give to other people's kids.

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

We're conditionally editing the return stack. This fits right in with
the earlier thread about conditionally removing code from the inside of
loops, IMO. Once you open this can, you might as well eat more than one
worm. Another conceptually similar notion is that of AUTOLOAD. As a perl
coder, I don't EVER want to write

  say Hello, world
or die Write to stdout failed.;

-- it's correct. It's safe coding.  And it's stupid for a
whole bunch of reasons, mostly involving the word yucky.



It's incorrect because it's distracting and tedious.

http://c2.com/cgi/wiki?IntentionNotAlgorithm

Code which does it is, IMHO bad code because obviously the author
does not know where to draw the line and say this is good enough,
anything more would only make it worse.
  


For instance, some 

Re: Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-10-01 Thread Austin Hastings
TSa wrote:


 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 ;)

 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.
 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!


The current state of the art dictates that exceptions are to be avoided
when it is possible to handle the error in-line. That exceptions should
only be used for exceptional cases, and anything you encounter in the
manual pages is not exceptional.

I don't agree with this, because it is IMO effectively saying We had
this powerful notion, but it turned out to be difficult to integrate
post-hoc into our stack-based languages, so we're going to avoid it.
Rather than admitting defeat, though, we're going to categorize it as
some kind of marginal entity.

I don't see exceptions as necessarily being outside the intrinsic
causality of the running program. They are non-traditional forms of flow
control: event-based programming, if you will, in an otherwise
sequential program.

We do much the same thing when we talk about coroutines: violate the
traditional stack model. We do the same thing again when we talk about
aspects: de-localize processing of certain (ahem) aspects of the problem
domain. The telling part of aspects, though, was the the first popular
implementation (AspectJ) required a preprocessor and a special markup
language to implement. Why? Because nobody uses extensibility and Java
in the same sentence. I guess aspects are traditional in that regard,
though: remember CFront. Perl, OTGH, doesn't have the poor body-image or
whatever it is that keeps people afraid to change the syntax.

 It can't be a method because it never returns to it's caller - it's


 It beeing the CATCH block? 


Ahh, no. It in this case is the .resume call. My question was is
cresume/c a multi, an object method, or what?

 This is because the types of exceptions I would want to resume are
 ones that have a distinct cause that can be mined from the exception
 object, and which my code can unambiguously fix without breaking the
 encapsulation of the code that raised the exception.


 Agreed. I tried to express the same above with my words.
 The only thing that is a bit underspecced right now is
 what exactly is lost in the process and what is not.
 My guiding theme again is the type system where you leave
 information about the things you need to be preserved to
 handle unusual cicumstances gracefully---note: *not*
 successfully, which would contradict the concept of exceptions!


This is the classical view of exceptions, and so it is subject to the
classical constraints: you can't break encapsulation, so you can't
really know what's going when the exception occurs.

The reason I like the with approach is that it lets us delocalize the
processing, but does _not_ keep the exceptions are violent,
incomprehensible events which wrench us from our placid idyll mentality.

In that regard, exceptuations are resumable gotos.

=Austin



Re: Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-10-01 Thread Yuval Kogman
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 

Re: Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-09-30 Thread TSa

HaloO,

Yuval Kogman wrote:

The try/catch mechanism is not like the haskell way, since it is
purposefully ad-hoc. It serves to fix a case by case basis of out
of bounds values. Haskell forbids out of bound values, but in most
programming languages we have them to make things simpler for the
maintenance programmer.


My view here is that the parameters in the code pick a point in
the range from free on the one end and bound at the other end.
The unifying concept is constraints. So I see the following boundary
equalities:

  unconstraint = free  # 0.0
  contstraint  # 0.0^..^1.0
  fully constraint

as the black and white ends with shades of gray in the middle.
And it is the type system that guaranties the availability
of the required information e.g. in $!. In that sense a sub
with a CATCH block is a different type than one without. This
difference is taking into account when dispatching exceptions.



Reentrancy is an implementation detail best left unmentioned.


Uh ohh, in an imperative language with shared state outside
the unshared state of multiple invocations of one sub the reentrance
proplem is just there. Interestingly it is easily unifyable with
shared data.



Assume that every bit of code you can run in perl 6 is first class
code - it gets safety, calls, control flow, exceptions, and so
forth.


Just to synchronize our understanding, I see the following
equivalences from the data and code domains

datacode

class = sub
 instance = invocation

To illustrate my view consider

class foo
{
   has ...
   method ...
}

and match with

sub foo
{
   has ... # my named parameters defined in body proposal

   BEGIN ...
   CATCH ...

   label:
}

What I want to say is that calling a sub means creating an
instance of the class that describes---or *constrains*---
the potential invocations. If such an invocation is left
lying in memory unfinished we have a continuation. How concurrent
these continuations are stepped in real time with respect to their
respective inner causal logic is irrelevant to the concept.
But *causality* is important!

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 ;)

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.
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!



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




It can't be a method because it never returns to it's caller - it's


It beeing the CATCH block? Then I think it *is* in a certain
way a method with $! as it's invocant. HiHi and here a locality
metric for dispatch applies. BTW, how is the signature of a CATCH
block given? Simply

   CATCH SomeException {...}

or is inspection with cascaded when mandatory?



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.


and returns not to the code which continued it, but to the code that
would have been returned to if there was no exception.


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



It is, IMHO a multi though. There is no reason that every
continuation cannot be a multi, because a continuation is just a
sub.

I don't know if there are method continuations - i guess there could
be, but there's no need to permutate all the options when the
options can compose just as well.


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

  1) the invocant type is determined
  2) the dispatcher selects a matching target
  3) this method maker object (like a class for constructing data objects)
 is asked to create a not yet called invocation and bind it to the
 invocant at hand
  4) at that moment we have a not yet invoked sub instance, so
 plain subs just start here
  5) The signature is checked and bound in the environment of the calling
 scope, the callers return continuation is one of the args
  6) then this invocation is activated
  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 

Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-09-29 Thread Austin Hastings
TSa wrote:

 HaloO,

 Yuval Kogman wrote:

 On Wed, Sep 28, 2005 at 11:46:37 -0500, Adam D. Lopresto wrote:

 The recent thread on Expectuations brought back to mind something
 I've been
 thinking for a while.  In short, I propose that use fatal be on by
 default, and
 that err be turned into syntactic sugar for a very small try/CATCH
 block.



You already know that err is the low-precedence version of //, right?
What replaces that? I like default or defaults myself, but I'm never
really sure what the precedence actually IS. After all, and/or were
lower than assignment, so you could code:

$a = foo or die;

and get ($a or die). How does this work for the err/defaults
keyword? Does the low-precedence version move up, or is there an idiom I
don't understand?

On the primary hand, I don't like the idea of using err as a try/catch
because that's putting exception handling in line with the primary code.
See FMTYEWT below.


 I like it a lot. It gives the advantages of both the flexible, more
 robust try/catch, and the (locally) concise, clear error return.


 I don't like it at all. I fear, that we mix two orthogonal concepts
 just because it is convenient.

 To me the statement

   return 42;  # 1

 has to orthogonal meanings:

   1) the current scope has reached its (happy) end
   2) a specific result was determined

 We can vary on both of these dimensions *independently*!
 Which gives the remaining three cases:

   return undef; #  0   unspecific result
   fail   undef; # -1   no return with unspecific reason
   fail   42;# -2   no return but  determined reason

 In other words an exception means

   return !caller;

 or in yet another way to describe my attitude: the least
 thing that *defines* an exception is that the dynamic
 scope in question has reached the conclusion that it
 is *not* going to give control back to its creator!


But it *does* give control, albeit briefly, back to its caller.

A million years ago, $Larry pointed out that when we were able to use
'is just a' classifications on P6 concepts, it indicated that we were
making good forward progress. In that vein, let me propose that:

* Exception handling, and the whole try/catch thing, IS JUST An awkward
implementation of (late! binding) run-time return-type MMD.

Specifically, if I promise you:

  sub foo() will return Dog;

and later on I actually wind up giving you:

  sub foo() will return Exception::Math::DivisionByZero;

the try/catch paradigm essentially says:

I wanted to call csub Dog foo()/c but there may be times when I
discover, after making the call, that I really needed to call an anonymous
csub { $inner::= sub Exception foo(); $e = $inner(); given $e {...} }/c.

We're conditionally editing the return stack. This fits right in with
the earlier thread about conditionally removing code from the inside of
loops, IMO. Once you open this can, you might as well eat more than one
worm. Another conceptually similar notion is that of AUTOLOAD. As a perl
coder, I don't EVER want to write

  say Hello, world
or die Write to stdout failed.;

-- it's correct. It's safe coding. And it's stupid for a whole bunch
of reasons, mostly involving the word yucky. But I acknowledge that
through the miracle of broken pipes, it can legitimately happen that
stdout will fail while stderr is a viable diagnostic mechanism.

Instead, I want PERL to fill that in for me: I believe that the default
error mechanism should debug my program, the shell script that calls my
program, and the actions (including blood alcohol content) of the user
of my program over the last 24 hours: lets leave cuse autodebug;/c
turned on by default.

The 'Exceptuation' proposal seems to me to include two things:

1. A 'RESUME' feature.
2. An implicit acknowledgement that the default implementations are
parallel:

{...
  CATCH  - $e {throw $e;} # Going up?
  RESUME - $r {resume $r;} # Going down?
}

The rest is optimization. If caller() includes an array of
continuations, then cthrow/c looks like a loop up the array:

  sub throw(Exception $e)
  {
reverse caller() == { .continuation($! = $e) if does(CATCH); }
  }

But the default behavior (modulo threads) is going to unlink all the
stack frame pages when the continuation is invoked. So there has to be
yet another copy of the links to the stack, because the exception
handling will want to call functions and build who-knows-what elaborate
skycastles. And it must be reentrant because of the possibility of
exceptions during the exception handling. Which means that the call
stack needs to be stored in the Exception. [The list of things in the
exception gets pretty long. I'm sure it's all a ref to the last page of
the call stack, so it doesn't gobble up much space, but there's a lot of
and you'll wants coming up.]

So cresume/c is a multi, no? (Or it could just be a method:
$!.resume, but that doesn't read as well in a block that *really* should
be as readable as possible.) Also, any layer of exception handling may
do some 

Re: Exceptuations, fatality, resumption, locality, and the with keyword; was Re: use fatal err fail

2005-09-29 Thread Yuval Kogman
On Thu, Sep 29, 2005 at 13:52:54 -0400, Austin Hastings wrote:

 You already know that err is the low-precedence version of //, right?
 What replaces that? I like default or defaults myself,

Yes, he proposed 'dor'.

As I see it err is like this:

sub infix:err ($lhs is delayed, $rhs is delayed) { # we really need 
thunk parameters
return $lhs dor $rhs;
CATCH { return $rhs }
}

So really 'err' is just 'dor' with an added error silencer.

 On the primary hand, I don't like the idea of using err as a try/catch
 because that's putting exception handling in line with the primary code.
 See FMTYEWT below.

Isn't

no fatal;

my $fh = open $file or die;
...
my $fh = open $file or next;

also putting exception handling in line with the primary code?

Isn't that useful?

Exception handling should be put in wherever there is well defined
behavior on how error conditions should be dealt with.

It's Perl's job to make this as easy as possible for the programmer.

If we have a module called File::Slurp::Some, which doesn't really
care if some of the files don't exist, it's code would, IMHO be
much more readable with

open $file err next;

than a catch block.

The reason for this is that a catch block is always detached from
the code.

However, if the error is part of the normal flow (it is no longer
exceptional for the file to not exist), what benefit does the added
detachment give?

 A million years ago, $Larry pointed out that when we were able to use
 'is just a' classifications on P6 concepts, it indicated that we were
 making good forward progress. In that vein, let me propose that:
 
 * Exception handling, and the whole try/catch thing, IS JUST An awkward
 implementation of (late! binding) run-time return-type MMD.

Exception handling is just continuation passing style with sugar.

Have a look at haskell's either monad. It has two familiar keywords
- return and fail.

Every statement in a monadic action in haskell is sequenced by using
the monadic bind operator.

The implementation of =, the monadic bind operator, on the Either
type is one that first check to see if the left statement has
failed. If it does, it returns it. If it doesn't it returns the
evaluation of the right hand statement.

Essentially this is the same thing, just formalized into a type

 Specifically, if I promise you:
 
   sub foo() will return Dog;
 
 and later on I actually wind up giving you:
 
   sub foo() will return Exception::Math::DivisionByZero;

In haskell:

foo :: Either Dog Exception::Math::DivisionByZero

e.g., it can return either the expected type, or the parameter.

Haskell is elegant in that it compromises nothing for soundness, to
respect referential integrity and purity, but it still makes thing
convenient for the programmer using things such as monads


 the try/catch paradigm essentially says:
 
 I wanted to call csub Dog foo()/c but there may be times when I
 discover, after making the call, that I really needed to call an anonymous
 csub { $inner::= sub Exception foo(); $e = $inner(); given $e {...} }/c.

Yes and no.

The try/catch mechanism is not like the haskell way, since it is
purposefully ad-hoc. It serves to fix a case by case basis of out
of bounds values. Haskell forbids out of bound values, but in most
programming languages we have them to make things simpler for the
maintenance programmer.

 We're conditionally editing the return stack. This fits right in with
 the earlier thread about conditionally removing code from the inside of
 loops, IMO. Once you open this can, you might as well eat more than one
 worm. Another conceptually similar notion is that of AUTOLOAD. As a perl
 coder, I don't EVER want to write
 
   say Hello, world
 or die Write to stdout failed.;
 
 -- it's correct. It's safe coding.  And it's stupid for a
 whole bunch of reasons, mostly involving the word yucky.

It's incorrect because it's distracting and tedious.

http://c2.com/cgi/wiki?IntentionNotAlgorithm

Code which does it is, IMHO bad code because obviously the author
does not know where to draw the line and say this is good enough,
anything more would only make it worse.

 But I acknowledge that through the miracle of broken pipes, it can
 legitimately happen that stdout will fail while stderr is a viable
 diagnostic mechanism.

the default $SIG{PIPE} handler is a wonderful example of how nice
exception handling is for naive code.

$SIG{PIPE}'s only problem is that it's completely non standard.

 But the default behavior (modulo threads) is going to unlink all the
 stack frame pages when the continuation is invoked.

Forget the stack... Perl is CPS under the hood, even if it's
optimized not to be that way.

 So there has to be yet another copy of the links to the stack,
 because the exception handling will want to call functions and
 build who-knows-what elaborate skycastles. And it must be
 reentrant because of