www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - improving scope(finally/success)

reply Tomer Filiba <tomerfiliba gmail.com> writes:
it'd be really helpful if scope() statements got hold of the 
return value or exception, e.g.,

scope(success, retval) {
     writeln("the retval is", retval)
}

scope(failure, ex) {
     if(typeid(ex) == typeid(MyException)) {
         callTheCops();
     }
}

it would make logging very easy, and since these statements are 
basically code-rewrites i don't suppose it would be hard to 
implement. from a syntax point of view:

scope(succes[, VARNAME])    // where VARNAME would be the return 
value (a const tmp variable?)
scope(failure[, VARNAME])   // where VARNAME would be hold the 
exception (a Throwable)

i mean, code such as

int f() {
     scope(exit) writeln("bye");
     return 5;
}

is rewritten as something like

int f() {
     try {
         auto tmp = 5;
     }
     finally {
         writeln("bye");
     }
     return tmp;
}

so `tmp` is already there for the finally clause (modulo scoping 
issues)
Dec 03 2015
next sibling parent reply Idan Arye <GenericNPC gmail.com> writes:
On Thursday, 3 December 2015 at 11:41:29 UTC, Tomer Filiba wrote:
 it'd be really helpful if scope() statements got hold of the 
 return value or exception, e.g.,

 scope(success, retval) {
     writeln("the retval is", retval)
 }

 scope(failure, ex) {
     if(typeid(ex) == typeid(MyException)) {
         callTheCops();
     }
 }

 it would make logging very easy, and since these statements are 
 basically code-rewrites i don't suppose it would be hard to 
 implement. from a syntax point of view:

 scope(succes[, VARNAME])    // where VARNAME would be the 
 return value (a const tmp variable?)
 scope(failure[, VARNAME])   // where VARNAME would be hold the 
 exception (a Throwable)

 i mean, code such as

 int f() {
     scope(exit) writeln("bye");
     return 5;
 }

 is rewritten as something like

 int f() {
     try {
         auto tmp = 5;
     }
     finally {
         writeln("bye");
     }
     return tmp;
 }

 so `tmp` is already there for the finally clause (modulo 
 scoping issues)
int foo(bool cond) { // scope 1 { // scope 2 scope(success, retval) { writeln("the retval is", retval) } if (cond) { // scope 3 return 1; } } return 2; } `foo(true)` should obviously print "the retval is 1", but what should `foo(false)` print? It's `scope(success)` block should run when it exists scope 2, but the return value is only determined at the end of scope 1.
Dec 03 2015
parent Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Thursday, 3 December 2015 at 13:07:53 UTC, Idan Arye wrote:
 On Thursday, 3 December 2015 at 11:41:29 UTC, Tomer Filiba 
 wrote:
 int f() {
     scope(exit) writeln("bye");
     return 5;
 }

 is rewritten as something like

 int f() {
     try {
         auto tmp = 5;
     }
     finally {
         writeln("bye");
     }
     return tmp;
 }

 so `tmp` is already there for the finally clause (modulo 
 scoping issues)
int foo(bool cond) { // scope 1 { // scope 2 scope(success, retval) { writeln("the retval is", retval) } if (cond) { // scope 3 return 1; } } return 2; } `foo(true)` should obviously print "the retval is 1", but what should `foo(false)` print? It's `scope(success)` block should run when it exists scope 2, but the return value is only determined at the end of scope 1.
Tomer's suggested lowering can't work, because tmp's scope doesn't extend outside of the try. It would need to be hoisted up to the beginning of the function. This would then imply that `foo(false)` would print "0" (int.init). However, I don't think this kind of lowering is a good idea, because it would create a temporary lvalue, which implies that it needs to go through the full construct/assign/destroy cycle instead of a simple move, which is a potentially observable difference to the current behaviour.
Dec 03 2015
prev sibling parent reply Chris Wright <dhasenan gmail.com> writes:
You can already do it with a slight change, and it's not so painful, at 
least in simple functions:

int foo(bool b) {
  auto result = 2;
  scope(exit) writeln(result);
  if (b) {
    result = 1;
  }
  return result;
}
Dec 03 2015
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/3/15 10:24 AM, Chris Wright wrote:
 You can already do it with a slight change, and it's not so painful, at
 least in simple functions:

 int foo(bool b) {
    auto result = 2;
    scope(exit) writeln(result);
    if (b) {
      result = 1;
    }
    return result;
 }
auto ref logCall(alias f, Args...)(auto ref Args args) { auto ref printResult(T)(auto ref T t) { writeln(t); return t; } return printResult(f(args)) } logCall!foo(true); -Steve
Dec 03 2015
parent Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 12/03/15 16:33, Steven Schveighoffer via Digitalmars-d wrote:
 auto ref logCall(alias f, Args...)(auto ref Args args) {
    auto ref printResult(T)(auto ref T t)
    {
       writeln(t);
       return t;
    }
    return printResult(f(args))
 }
 
 logCall!foo(true);
Which will happily accept: bool foo(ref bool a) { return a=false; } And, yes, it can be dealt with via a bit of introspection, but nobody will bother in practice (consider that 'f' may be overloaded). So it doesn't really work for non-trivial or generic code. artur
Dec 04 2015