www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - This feels wrong

reply Shachar Shemesh <shachar weka.io> writes:
Please consider the following program:
import std.stdio;

struct A {
     int opApply( scope int delegate(int) dg ) {
         foreach(int i; 0 .. 50) {
             try {
                 int res = dg(i);
                 if( res!=0 ) {
                     writefln("Delegate returned %s", res);
                     return res;
                 }
             } catch(Exception ex) {
                 writefln("Caught in loop: %s", ex.msg);
             }
         }

         return 0;
     }
}

void main() {
     try {
         A a;
         foreach(i; a) {
             writefln("Loop got %s", i);

             if( i==10 ) {
                 throw new Exception("Excccption");
             }

             if( i==20 ) {
                 break;
             }
         }
     } catch( Exception ex ) {
         writefln("Caught outside of loop: %s", ex.msg);
     }
}

When run, I expected the loop to break after 10 iterations due to the 
exception being thrown. Instead, the loop continued.

The problem with this is that, sometimes, the task generating the loop 
might, itself, require exception handling. Distinguishing between the 
exceptions thrown inside the delegate and outside it becomes a somewhat 
tricky exercise.

At the very least, I think this behaviour should be documented.

Thoughts?

Shachar
Feb 02 2016
next sibling parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
It seems this is a natural consequence of the lowering. As such, 
I'm not surprised by the behaviour, of course under the 
assumption I - as an end user - actually know that the given 
opApply catches the exception. I guess there could be a 
recommendation in opApply's specification that implementors 
shouldn't needlessly catch exceptions, especially not unspecific 
ones like `Exception`, but if they do, they should rethrow them, 
or better yet use scope(exit/finally) and try/finally as 
appropriate.
Feb 02 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/2/16 4:44 AM, Shachar Shemesh wrote:
 Please consider the following program:
 import std.stdio;

 struct A {
      int opApply( scope int delegate(int) dg ) {
          foreach(int i; 0 .. 50) {
              try {
                  int res = dg(i);
                  if( res!=0 ) {
                      writefln("Delegate returned %s", res);
                      return res;
                  }
              } catch(Exception ex) {
                  writefln("Caught in loop: %s", ex.msg);
              }
          }

          return 0;
      }
 }

 void main() {
      try {
          A a;
          foreach(i; a) {
              writefln("Loop got %s", i);

              if( i==10 ) {
                  throw new Exception("Excccption");
              }

              if( i==20 ) {
                  break;
              }
          }
      } catch( Exception ex ) {
          writefln("Caught outside of loop: %s", ex.msg);
      }
 }

 When run, I expected the loop to break after 10 iterations due to the
 exception being thrown. Instead, the loop continued.

 The problem with this is that, sometimes, the task generating the loop
 might, itself, require exception handling. Distinguishing between the
 exceptions thrown inside the delegate and outside it becomes a somewhat
 tricky exercise.

 At the very least, I think this behaviour should be documented.

 Thoughts?
Just put try around the opApply specific parts you want to monitor. Don't guard the call to dg. -Steve
Feb 02 2016
parent reply Shachar Shemesh <shachar weka.io> writes:
On 02/02/16 17:00, Steven Schveighoffer wrote:

 Just put try around the opApply specific parts you want to monitor.
 Don't guard the call to dg.
The call to dg is, obviously, part of a loop. That whole loop body is inside a try/catch. What I ended up doing, instead, was to put a flag, and the call to dg is, effectively: stuff... { scope(failure) flags=true; dg(); } more stuff... and then, the catch: catch(Exception ex) { if( flags ) throw ex; other stuff... } My problem isn't so much the actual how to solve it, but rather that it is a potential pitfall when implementing that I don't think is documented. Shachar
Feb 02 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 2/2/16 10:21 AM, Shachar Shemesh wrote:
 On 02/02/16 17:00, Steven Schveighoffer wrote:

 Just put try around the opApply specific parts you want to monitor.
 Don't guard the call to dg.
The call to dg is, obviously, part of a loop. That whole loop body is inside a try/catch.
I don't see a big difference from this: int opApply( scope int delegate(int) dg ) { foreach(int i; 0 .. 50) { int res = dg(i); try { if( res!=0 ) { writefln("Delegate returned %s", res); return res; } } catch(Exception ex) { writefln("Caught in loop: %s", ex.msg); } } return 0; }
 My problem isn't so much the actual how to solve it, but rather that it
 is a potential pitfall when implementing that I don't think is documented.
OK, I understand what you are saying. It could be listed in the docs as something to avoid. -Steve
Feb 02 2016
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 02/02/2016 07:21 AM, Shachar Shemesh wrote:

 it is a potential pitfall when implementing that I don't think is
 documented.
Good catch! Please either open a documentation bug for this or fork the repo and fix it yourself. :) (Hopefully, there is an 'Improve this page' link on that page.) Ali
Feb 02 2016
parent Shachar Shemesh <shachar weka.io> writes:
On 02/02/16 21:24, Ali Çehreli wrote:
 On 02/02/2016 07:21 AM, Shachar Shemesh wrote:

  > it is a potential pitfall when implementing that I don't think is
  > documented.

 Good catch! Please either open a documentation bug for this or fork the
 repo and fix it yourself. :) (Hopefully, there is an 'Improve this page'
 link on that page.)

 Ali
https://github.com/D-Programming-Language/dlang.org/pull/1224
Feb 03 2016