scope(exit) considered harmful

Justin Johansson no at spam.com
Sun Nov 8 10:44:32 PST 2009


Ellery Newcomer Wrote:

> Justin Johansson wrote:
> > but in the D world beware the Ides of Scopes because if your curly
> > brace block with the true/false conditional contains a scope(exit)
> > you will get explainable but unexpected behaviour if this code
> > is enabled inside an if(true) block.
> 
> Elaboration?

Thanks for asking.  Sorry for delay in reply due my timezone.  Currently
5 am and waked due to heat wave in my neck of the woods.

I've stripped my dev code down to basics to demonstrate what happened
to me.  (This is from my scripting language project being developed in D).

// (Replace auto with proper typename to make things clearer for the example.)

Expr compile( string statement) {
   // compile statement to some "expression" node
   // note that this method might throw a syntax error
   Expr expr = ...
   return expr;
}

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {
   // push someOtherExpr onto some internal stack;
   // compile new expression node and execute result
   // via the apply callback; pop the internal stack
   // when done.

   // Use try/finally back to ensure internal stack is
   // popped in case compile throws an exception
   try {
      pushExpr( someOtherExpr);
      Expr newExpr = compile( statement);
      return apply( newExpr);
   }

   finally {
      popExpr();
   }
}


// Hey, let's tidy this up with D's you-beaut scope(exit) thing.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {
   // push someOtherExpr onto some internal stack;
   // compile new expression node and execute result
   // via the apply callback; pop the internal stack
   // when done (guarding against compile exception)

   pushExpr( someOtherExpr);
   scope(exit) popExpr();

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// Cool, I think I like this better.  Let's test it.
// Okay we know apply is meant to fail if we don't do
// the push/pop thing.  Test by commenting out.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   //pushExpr( someOtherExpr);
   //scope(exit) popExpr();

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// Yep, apply failed as expected.  Play around for a
// bit longer turning the push/pop thing off and on.
// Note used /+ +/ this time.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   /+
   pushExpr( someOtherExpr);
   scope(exit) popExpr();
   +/

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// Yep, all good.  Play around for a bit longer turning
// the push/pop thing off and on. Getting sick of hitting
// two lines to comment out.  try if (false) instead --
// then just one line to hit.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   if (false) {
      pushExpr( someOtherExpr);
      scope(exit) popExpr();
   }

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// Yep, all good.  Failures working as expected.
// Turn the push/pop thing back on.  Leave the if
// statement in place for moment just in case we
// wanna mess around more later.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   if (true) {
      pushExpr( someOtherExpr);
      scope(exit) popExpr();
   }

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// What the F*&%$~?  This doesn't work any more.  It used too.

// After some ***lengthy*** amount of time wasted trying to figure this out.

// ...

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   pushExpr( someOtherExpr);
   scope(exit) popExpr();

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


// Works again.  Penny drops -- scope(exit) activates
// when leaving the if (true) {...} statement and not at
// function scope.  True the D doco says that;  Guess I
// should have used a static if for testing.

int compileAndExecute( Expr someOtherExpr, string statement, int delegate( Expr expr) apply) {

   static if (true) {
      pushExpr( someOtherExpr);
      scope(exit) popExpr();
   }

   Expr newExpr = compile( statement);
   return apply( newExpr);
}


Can you understand my frustration?

-- Justin




More information about the Digitalmars-d mailing list