Re: [PHP-DEV] Re: 回复: [PHP-DEV] resume after exception

2012-04-06 Thread Rasmus Schultz
2012/4/5 Anthony Ferrara ircmax...@gmail.com:
 Why not just do:

 function foo(callable $callback) {
    $a = 0;
    $callback();
    $a = 1;
    $callback();
 }

 function bar() {
    foo(function() { echo 1; });
 }

 It's functionally the same, but doesn't have the stack magic.

 Now, it won't be able to do everything that your concept does (bubble
 up to an arbitrary point), but I see that as a good thing, since this
 is explicit.  And considering that you're intending to use it as a
 control flow structure (which is not what exceptions are supposed to
 be), I would say exceptions and their dynamic nature would be
 literally a bad thing in this case...

I don't see how exceptions are anything but a control flow structure?

If all you wanted was an error-message, you'd be using trigger_error()
- the only way exceptions differ, is that they allow execution to
continue from a certain point, under certain circumstances; it allows
you to control the flow.

 It's functionally the same, but doesn't have the stack magic.

your argument and example above is certainly valid, but from the same
point of view, why not get rid of throw/try/catch statements too while
we're at it?

function foo(callabable $errorhandler)
{
  if (some_condition()) {
$errorhandler();
  }
}

function bar() {
  foo(function() { echo 'an error occurred!'; exit; });
}

This works just as well, and as you pointed out, it's probably easier
to understand.

Now, it won't be able to do everything that an exception does (bubble
up to an arbitrary point), but you could view that as a good thing,
since this is explicit. You could argue that exceptions and their
dynamic nature is literally a bad thing in every case.

To your technical point:

 This could get really ugly as you'd be
 forced to have multiple stacks hanging around if you used more than
 one of these in your code.

I don't see how?

If you throw an interrupt, and nothing catches it, the program
terminates, same as after an exception.

if you throw an interrupt and something catches it, that interrupt
(and it's retained stack) only lives for the duration of the
catch-statement:

try {
  ...
} catch (Interrupt $i) {
  if (some_condition())
resume; // (A)
  else if (other_condition())
throw $i; // (B)
  // (C)
}

There are three ways you can exit this catch{} block:

(A) we resume execution from the throw-statement, and the previous
stack remains valid.

(B) the previous stack is preserved for another catch-statement (or
exit with an error-message)

(C) if we exit the catch{}-block and don't resume, it is safe to
unwind the stack at this point. (assuming we're talking about just
interrupts, and not continuations that can be serialized and resumed
at a later time.)

I don't know why you think interrupts are so unnatural or difficult to
understand - to me, it would be a natural extension of exceptions. And
I've never understood why they are so frequently compared to GOTO. I
think it's entirely a matter of how you perceive (and apply) the idea
of exceptions - personally I see them not as a better replacement
for triggering errors, I really can't see them as anything other than
flow-control statements; there are few cases from which it is really,
truly impossible to recover, but when I identify such a case, I still
use trigger_error() - and granted, this is rare, but there are cases.

And mind you, registering an error-handler was possible before
exceptions were around, and we got by then - just because something
works or is well-established, doesn't mean there is no room for
improvement.

I'm not going to pretend I know enough about programming languages to
say for sure that this is a good idea - if this idea has been tried or
researched and proven bad already, I'd love to learn about it. But
if so, I doubt it was for any of the reasons I've heard so far...

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: 回复: [PHP-DEV] resume after exception

2012-04-06 Thread Anthony Ferrara
Rasmus,

I think you're missing the difference here.  Let's look at an exception.

try {
doFoo();
throwsException();
doBar();
} catch (Exception $e) {
doBaz();
}

This is NOT the same as:

doFoo();
throwsException('doBaz');
doBar();

To emulate the exception using continuation passing, you'd need to
pass two functions, a success and a failure.

doFoo();
throwsException('doBaz', 'doBar');

And that's for a single stack level.  Imagine how complicated it would
become if you were dealing with a large stack or multiple throwers.
You'd have something like this:

doFoo();
throwsException1(function() {
throwsException2(function() {
doBar();
},
function() {
throwsException3(function() {
doBaz();
},
function() {
doBiz();
}
});
}

It'll get really messy really quick.

As far as your point about keeping multiple stacks, imagine this code:

try {
throwsInterrupt();
doSomething();
} catch (Interrupt $i) {
callFuncThatInternallyCallsAnotherThatThrowsInterrup();
resume;
}

Now, you have 3 independent stacks that are raised.  The one for the
original call to throwsInterrupt, one for the function that internally
calls another that throws, and one for the internal interrupt itself.
All three would need to be detached at some point from the execution
stack and saved for resume.  So you're not only unwinding the stacks,
but saving them as well incase the interrupt is resumed (to re-wind
the stack).

Right now, Exceptions don't have this problem, since the stack is
never rewound.  So it only grows or is unwound based on the exception
tree...

Not to mention that code execution is always linear in an exception
case.  It's not possible that code flow will magically jump around.
Sure, you could emulate it with goto (
http://codepad.viper-7.com/i3Dhv4 ).  But that's explicitly jumping
around.

Anthony

On Fri, Apr 6, 2012 at 9:31 AM, Rasmus Schultz ras...@mindplay.dk wrote:
 2012/4/5 Anthony Ferrara ircmax...@gmail.com:
 Why not just do:

 function foo(callable $callback) {
    $a = 0;
    $callback();
    $a = 1;
    $callback();
 }

 function bar() {
    foo(function() { echo 1; });
 }

 It's functionally the same, but doesn't have the stack magic.

 Now, it won't be able to do everything that your concept does (bubble
 up to an arbitrary point), but I see that as a good thing, since this
 is explicit.  And considering that you're intending to use it as a
 control flow structure (which is not what exceptions are supposed to
 be), I would say exceptions and their dynamic nature would be
 literally a bad thing in this case...

 I don't see how exceptions are anything but a control flow structure?

 If all you wanted was an error-message, you'd be using trigger_error()
 - the only way exceptions differ, is that they allow execution to
 continue from a certain point, under certain circumstances; it allows
 you to control the flow.

 It's functionally the same, but doesn't have the stack magic.

 your argument and example above is certainly valid, but from the same
 point of view, why not get rid of throw/try/catch statements too while
 we're at it?

 function foo(callabable $errorhandler)
 {
  if (some_condition()) {
    $errorhandler();
  }
 }

 function bar() {
  foo(function() { echo 'an error occurred!'; exit; });
 }

 This works just as well, and as you pointed out, it's probably easier
 to understand.

 Now, it won't be able to do everything that an exception does (bubble
 up to an arbitrary point), but you could view that as a good thing,
 since this is explicit. You could argue that exceptions and their
 dynamic nature is literally a bad thing in every case.

 To your technical point:

 This could get really ugly as you'd be
 forced to have multiple stacks hanging around if you used more than
 one of these in your code.

 I don't see how?

 If you throw an interrupt, and nothing catches it, the program
 terminates, same as after an exception.

 if you throw an interrupt and something catches it, that interrupt
 (and it's retained stack) only lives for the duration of the
 catch-statement:

 try {
  ...
 } catch (Interrupt $i) {
  if (some_condition())
    resume; // (A)
  else if (other_condition())
    throw $i; // (B)
  // (C)
 }

 There are three ways you can exit this catch{} block:

 (A) we resume execution from the throw-statement, and the previous
 stack remains valid.

 (B) the previous stack is preserved for another catch-statement (or
 exit with an error-message)

 (C) if we exit the catch{}-block and don't resume, it is safe to
 unwind the stack at this point. (assuming we're talking about just
 interrupts, and not continuations that can be serialized and resumed
 at a later time.)

 I don't know why you think interrupts are so unnatural or difficult to
 understand - to me, it would be a natural extension of exceptions. And
 I've never understood why they are so frequently compared to GOTO. I
 think 

[PHP-DEV] Re: 回复: [PHP-DEV] resume after exception

2012-04-05 Thread Rasmus Schultz
interesting, but this doesn't have anything in particular to do with
what I was talking about.

to the best of my understanding, an exception transfers control back
to the nearest calling code that has declared it is ready/willing/able
to resume control in the event that, somewhere up the call-stack, a
condition occurs that causes an exception.

it's a wonderful mechanism with more uses than simply reporting errors
- the aspect of transferring control is what I find really interesting
about exceptions.

with regards to transferring control, why does it strike you as so
unnatural to also provide a mechanism for returning control?

to me, it seems like a perfectly natural extension of that mechanism -
and of course, not as something that just happens, but as a feature
you can opt into.

since breaking program flow is already supported by exceptions, and
since that is the first half of the mechanism I have in mind, I
thought it would be natural to have an extended type of exception (I
called it an interrupt) where it is also possible to resume program
flow after the throw-statement.

the way I defined it, as with exceptions, this requires a formal
declaration to do so, both on the part of the throwing code, and on
the part of the code that catches and assumes control after the throw.
exceptions aren't guaranteed to be handled, and similarly, there's no
guarantee that control will be returned to the throwing code after an
interrupt. for all intents and purposes, it's still an exception, and
can be handled as an exception too - the difference is, by throwing an
interrupt, you've agreed to possibly resuming execution after the
interrupt is handled, if the interrupt is caught and the catching code
decides to return control.

it's not a one-way transfer of control like a goto, where you have to
test for conditions and decide where to transfer control on a
case-by-case basis. in my mind, the term spaghetti doesn't describe
the program itself, but the more or less unpredictable execution path,
which can only be understood by trying to execute the program in
your mind. exceptions (and what I call an interrupt) does not allow
you to sporadically transfer control just anywhere, but rather follows
the well-understood mechanics of an exception, with a hierarchical
execution path - just with the added benefit of returning control from
the exception-handler after catching and handling it.

taking this one step further (with state-serialization and
continuation) was just an afterthought, something that occurred to me
while I was typing - that may be taking it too far, and really wasn't
something I've been thinking about deeply...


On Tue, Apr 3, 2012 at 3:28 AM, reeze reeze@gmail.com wrote:

 If just for exception recovery how about implement ruby's retry ?

 http://www.tutorialspoint.com/ruby/ruby_loops.htm  Ruby retry statement
 section.


 在 2012年4月2日星期一,下午8:44,Rasmus Schultz 写道:

 I was just reading about the new async/await keywords in C# 5.0, and while
 this has no particular relevance to PHP as such, it got me thinking about
 this idea...

 What if you could resume execution after an exception was thrown?

 Fictive example:

 function test()
 {
 echo Begin Test!\n;

 throw new Interrupt();

 echo Execution resumed!;
 }

 try
 {
 test();
 }
 catch (Interrupt $e)
 {
 echo Execution interrupted.\n;
 resume;
 }

 The output of this would be:

 Begin Test!
 Execution interrupted.
 Execution resumed!

 In other words, Interrupt is a new type of Exception, from which you can
 recover, using the new resume keyword.

 Taking this one step further, imagine it were also possible to serialize()
 an Interrupt - and resume it at a later time. This would open up entirely
 new possibilities for (AJAX) web-application frameworks, which would be
 able to suspend execution, serialize the script state, return a response,
 wait for further interaction from the user, and then resume execution.

 I'm sure there are lots of problems with this idea, and perhaps it's not a
 good fit for PHP at all, but I figured it couldn't harm to put the idea
 out
 there anyway :-)

 Any thoughts?



-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP-DEV] Re: 回复: [PHP-DEV] resume after exception

2012-04-05 Thread Anthony Ferrara
Rasmus,

What would that give you that a continuation passing paradigm
wouldn't?  Why not tell the code what to call before you call it,
rather than bubbling up the stack (which then forces a fork of the
stack, as you need to partially unwind it, but keep track of what you
unwound for the resume).  This could get really ugly as you'd be
forced to have multiple stacks hanging around if you used more than
one of these in your code.
So, instead of:

function foo() {
$a = 0:
throw new Interrupt();
$a = 1;
throw new Interrupt();
}

function bar() {
try {
foo():
} catch (Interrupt $i) {
echo 1;
resume;
}
}

Why not just do:

function foo(callable $callback) {
$a = 0;
$callback();
$a = 1;
$callback();
}

function bar() {
foo(function() { echo 1; });
}

It's functionally the same, but doesn't have the stack magic.

Now, it won't be able to do everything that your concept does (bubble
up to an arbitrary point), but I see that as a good thing, since this
is explicit.  And considering that you're intending to use it as a
control flow structure (which is not what exceptions are supposed to
be), I would say exceptions and their dynamic nature would be
literally a bad thing in this case...

Anthony



2012/4/5 Rasmus Schultz ras...@mindplay.dk:
 interesting, but this doesn't have anything in particular to do with
 what I was talking about.

 to the best of my understanding, an exception transfers control back
 to the nearest calling code that has declared it is ready/willing/able
 to resume control in the event that, somewhere up the call-stack, a
 condition occurs that causes an exception.

 it's a wonderful mechanism with more uses than simply reporting errors
 - the aspect of transferring control is what I find really interesting
 about exceptions.

 with regards to transferring control, why does it strike you as so
 unnatural to also provide a mechanism for returning control?

 to me, it seems like a perfectly natural extension of that mechanism -
 and of course, not as something that just happens, but as a feature
 you can opt into.

 since breaking program flow is already supported by exceptions, and
 since that is the first half of the mechanism I have in mind, I
 thought it would be natural to have an extended type of exception (I
 called it an interrupt) where it is also possible to resume program
 flow after the throw-statement.

 the way I defined it, as with exceptions, this requires a formal
 declaration to do so, both on the part of the throwing code, and on
 the part of the code that catches and assumes control after the throw.
 exceptions aren't guaranteed to be handled, and similarly, there's no
 guarantee that control will be returned to the throwing code after an
 interrupt. for all intents and purposes, it's still an exception, and
 can be handled as an exception too - the difference is, by throwing an
 interrupt, you've agreed to possibly resuming execution after the
 interrupt is handled, if the interrupt is caught and the catching code
 decides to return control.

 it's not a one-way transfer of control like a goto, where you have to
 test for conditions and decide where to transfer control on a
 case-by-case basis. in my mind, the term spaghetti doesn't describe
 the program itself, but the more or less unpredictable execution path,
 which can only be understood by trying to execute the program in
 your mind. exceptions (and what I call an interrupt) does not allow
 you to sporadically transfer control just anywhere, but rather follows
 the well-understood mechanics of an exception, with a hierarchical
 execution path - just with the added benefit of returning control from
 the exception-handler after catching and handling it.

 taking this one step further (with state-serialization and
 continuation) was just an afterthought, something that occurred to me
 while I was typing - that may be taking it too far, and really wasn't
 something I've been thinking about deeply...


 On Tue, Apr 3, 2012 at 3:28 AM, reeze reeze@gmail.com wrote:

 If just for exception recovery how about implement ruby's retry ?

 http://www.tutorialspoint.com/ruby/ruby_loops.htm  Ruby retry statement
 section.


 在 2012年4月2日星期一,下午8:44,Rasmus Schultz 写道:

 I was just reading about the new async/await keywords in C# 5.0, and while
 this has no particular relevance to PHP as such, it got me thinking about
 this idea...

 What if you could resume execution after an exception was thrown?

 Fictive example:

 function test()
 {
 echo Begin Test!\n;

 throw new Interrupt();

 echo Execution resumed!;
 }

 try
 {
 test();
 }
 catch (Interrupt $e)
 {
 echo Execution interrupted.\n;
 resume;
 }

 The output of this would be:

 Begin Test!
 Execution interrupted.
 Execution resumed!

 In other words, Interrupt is a new type of Exception, from which you can
 recover, using the new resume keyword.

 Taking this one step further, imagine it were also possible to