February 28, 2006
>I'd say add another option to try..catch..finally paradigm.
>
>-S.

Seconded.  For more fun, next we can debate whether the syntax should be:

1.  try..pass..catch..finally
2.  try..catch..pass...finally
3.  try..catch..finally..pass


Tom


February 28, 2006
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:dtvkhr$2cf4$1@digitaldaemon.com...
>
> "Walter Bright" <newshound@digitalmars.com> wrote in message news:dtr8kl$4lm$1@digitaldaemon.com...
>>
>> "Derek Parnell" <derek@psych.ward> wrote in message news:op.s5j942tp6b8z09@ginger.vic.bigpond.net.au...
>>> Wow! I know of one other language that (almost) implements this.
>>
>> Which one?
>>
>
> If I understand this correctly Ruby has something similar http://www.rubycentral.com/book/tut_exceptions.html
>
> But this is the same try-catch-finally I guess
> as these on_scope_*** too, btw.

Ruby's rescue thing looks like try-catch. on_scope is much more than try-catch, or I wouldn't have implemented it <g>.


February 28, 2006
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:dtvl91$2dds$1@digitaldaemon.com...
>
> This is real life example:
>
> Logger log = getLogger();
> try {
>      File outf = getOutputFile(); // state managed outside
>      File inf = getInputFile(); // state managed outside
>      File tmpf = createTempFile();
>      // lots of code
> } catch (Object e)  {
>      log.logFailure("...");
>      throw e;
> } finally {
>     delete tmpf;
> }
> log.close();

I don't see how it could be real life, since tmpf is not in scope in the finally statement, so it won't compile. Furthermore, even if tmpf was in scope, if getOutputFile() throws, then tmpf wouldn't have even been created when the finally statement attempts to delete it. The log.close() also does not reliably happen, as the throw e; statement would cause it to be skipped.

These kinds of issues are what on_scope_xxx are for. Let's rewrite it:

Logger log = getLogger();
    on_scope_exit log.close();
    on_scope_failure log.logFailure("...");
File outf = getOutputFile();
File inf = getInputFile();
File tmpf = createTempFile();
    on_scope_exit delete tmpf;
...lots of code...

We don't have any more resource leaks.


February 28, 2006
On Tue, 28 Feb 2006 06:34:00 +0000 (UTC), Tom Johnson <Tom_member@pathlink.com> wrote:
>> I'd say add another option to try..catch..finally paradigm.
>>
>> -S.
>
> Seconded.  For more fun, next we can debate whether the syntax should be:
>
> 1.  try..pass..catch..finally
> 2.  try..catch..pass...finally
> 3.  try..catch..finally..pass

No, on_scope gives us more than try/catch/finally. Let me try this another way.

"catch" from try/catch/finally allows:
 - you to execute a static/pre-defined set of code in the event that there is a failure in the current scope.

"finally" from try/catch/finally allows:
 - you to execute a static/pre-defined set of code at the exit of the current scope in all cases.

Compare that to:

on_scope_failure allows:
 - you to add one or more sets of code, at the points at which they become required, to the list of things to execute in the event of a failure.

on_scope_exit allows:
 - you to add one or more sets of code, at the points at which they become required, to the list of things to execute at the exit of the scope in all cases.

To achieve the same thing that on_scope gives with try/finally requires you to store state somewhere to indicate which parts of the finally block to execute, or, it requires that you define several finally blocks and nest them. Both of those options are no where near as neat as on_scope.

I'm honestly baffled that people can't see the difference.

Regan
February 28, 2006
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:du0hhf$a0u$1@digitaldaemon.com...
> Why you think that your example is aesthetically
> better (technically they are the same) than this?
>
> Transaction abc()
> {
>    Foo f;   Bar b;  Def d;
>    try
>   {
>       f = dofoo();
>       b = dobar();
>       d = dodef();
>       return Transaction(f, b, d);
>   }
>   finally {
>      delete f; delete b; delete d;
>   }
> }

Technically, they are not the same. The above version *always* deletes f, b and d, but it's not supposed to if the function succeeds. Only if dofoo(), dobar(), or dodef() throws are f, b and d supposed to be deleted.

This is the whole problem with try-finally. It works great with trivial problems, and all the tutorials and example code unsurprisingly only show trivial problems. Try scaling it up for things like multi-step transactions, and it gets very complicated very fast, and it gets very hard to get right.

Here's the on_scope version:

Transaction abc()
{
    Foo f = dofoo();
        on_scope_failure delete f;
    Bar b = dobar();
        on_scope_failure delete b;
    Def d = dodef();
        on_scope_failure delete d;
    return Transaction(f, b, d);
}

Scaling it up is as easy as linearly adding more on_scope statements, and easy to get it right.


February 28, 2006
On Mon, 27 Feb 2006 12:40:56 -0500, Chris Miller wrote:

I find this one better too.

> On Sat, 25 Feb 2006 21:06:36 -0500, Walter Bright <newshound@digitalmars.com> wrote:
> 
>> Scope guards are a novel feature no other language has. They're based on Andrei Alexandrescu's scope guard macros, which have led to considerable interest in the idea. Check out the article www.digitalmars.com/d/exception-safe.html
>>
> 
> This format looks good to me:
> 
> scope(exit)  foo();
> scope(success)  bar();
> scope(failure)  baz();
> 
> similar to extern(name), pragma(name), etc, requires one `scope` keyword, name in () doesn't need to be a keyword but is still treated special, and doesn't look bad.

February 28, 2006
>
> Technically, they are not the same. The above version *always* deletes f, b and d, but it's not supposed to if the function succeeds. Only if dofoo(), dobar(), or dodef() throws are f, b and d supposed to be deleted.

Ok, mea culpa.

>
> This is the whole problem with try-finally. It works great with trivial problems, and all the tutorials and example code unsurprisingly only show trivial problems. Try scaling it up for things like multi-step transactions, and it gets very complicated very fast, and it gets very hard to get right.

Well, I spent year programming on PocketPC in eVC where are no such things as exceptions. In principle. Not implemented in C++ compiler. Still alive :)

>
> Here's the on_scope version:
>
> Transaction abc()
> {
>    Foo f = dofoo();
>        on_scope_failure delete f;
>    Bar b = dobar();
>        on_scope_failure delete b;
>    Def d = dodef();
>        on_scope_failure delete d;
>    return Transaction(f, b, d);
> }
>
> Scaling it up is as easy as linearly adding more on_scope statements, and easy to get it right.

True.

But
Transaction abc()
{
    try {
      Foo f = dofoo();
      Bar b = dobar();
      Def d = dodef();
      return Transaction(f, b, d);
   } catch(object er) {
        delete f; delete b; delete d;
   }
}
is not worse to be honest.

I would think rather about extending mixins to allow to add on_scope_exit as a custom template conrstructions.

Like mixins taking block {} as a parameter:

template on_scope_exit(B)  auto Auto t = new Auto(B);

... and in Galaxy far far away:

mixin on_scope_exit{ delete foo; }

So anyone can implement needed policy for himself.

I mean on_scope_exit is only one particular way of dealing with the problem. There are and will be others.

Huh?

Andrew.


February 28, 2006
"S. Chancellor" <dnewsgr@mephit.kicks-ass.org> wrote in message news:du0lmk$dbg$1@digitaldaemon.com...
> On 2006-02-25 18:06:36 -0800, "Walter Bright" <newshound@digitalmars.com> said:
>
>> Scope guards are a novel feature no other language has. They're based on Andrei Alexandrescu's scope guard macros, which have led to considerable interest in the idea. Check out the article www.digitalmars.com/d/exception-safe.html
>
> The only thing I see that's amazingly useful about this is the on_scope_success.  Having a block of code that is only executed when an exception is NOT thrown would be nice.  However, the rest of this stuff seems like rocks under the water.  Your example of the new programmer coming in reads like this to me:  "The new programmer may not take the time to actually read the code he's modifying, so lets stick hidden stuff in there to take care of things he might have missed."  Which doesn't seem very logical to me, as it may be just as important to modify those on success/on failure blocks and miss them.
>
> I'd say add another option to try..catch..finally paradigm.
>
> -S.
>

try {

   something horrible here....

   //on_scope_success:

   ... and here is on success part

}

Why do you need separate 'passed' part?

Andrew.







February 28, 2006
"Regan Heath" <regan@netwin.co.nz> wrote in message news:ops5n25std23k2f5@nrage.netwin.co.nz...
> On Mon, 27 Feb 2006 19:54:23 -0800, Andrew Fedoniouk <news@terrainformatica.com> wrote:
>> Seems like I realy don't understand something here...
>>
>> Why you think that your example is aesthetically
>> better (technically they are the same) than this?
>
> Wait, your example below is not technically the same as mine because:
>
> 1. My example (actually taken from the docs on digitalmars.com) used on_scope_failure, not on_scope_exit. on_scope_exit has the same effect as "finally" except...
>
> 2. The important feature of all of these statements is that they allow you to add items to the list of things to do _as you go_ and to then execute them in reverse lexical order at the appropriate time i.e. on_scope_exit or on_scope_failure etc.

BTW:
  Walter is using "reverse lexical order" incorectly in the doc I beleive.
  "lexical order" is something from different opera.


Andrew


February 28, 2006
"Andrew Fedoniouk" <news@terrainformatica.com> wrote in message news:du106f$ptt$1@digitaldaemon.com...
> Well, I spent year programming on PocketPC in eVC where are no such things as exceptions. In principle. Not implemented in C++ compiler. Still alive :)

It's true that if code doesn't generate exceptions, then one doesn't need exception safety.

> But
> Transaction abc()
> {
>    try {
>      Foo f = dofoo();
>      Bar b = dobar();
>      Def d = dodef();
>      return Transaction(f, b, d);
>   } catch(object er) {
>        delete f; delete b; delete d;
>   }
> }
> is not worse to be honest.

It is worse because it won't even compile. f, b, and d are not in scope in the catch statement. Even if they were, there's still a serious bug - if dofoo() throws an exception, then the catch statement will attempt to delete b and d, which are not even initialized yet.