On Wednesday, 16 January 2013 at 23:19:20 UTC, Andrej Mitrovic wrote:
Sample code:
I was expecting callScope to be lowered down to the handwritten code in callFunc in assembly, but instead it uses exceptions. Here's some simple ASM for callFunc compiled with -c -release -O (no inline):


 <snip>

I'm trying to understand why. If an exception is thrown between one of those assignment statements the stack will unwind and any following assignment statements will not be called, so there shouldn't be a need to check if an exception is thrown. Why doesn't the compiler simply rewrite callScope to look like callFunc?

Obviously your code won't throw, however that's now how scope works.

TDPL. pg 84-88 explains the lowering of scope is equal to hand written try/catch/finally versions; But you don't have to worry about making a mistake in the writing and adding more scopes is easier. Handling SQL and several tasks that all need to succeed or certain steps to be cleaned up afterwards makes perfect sense for scope.

[quote]
 Consider a block containing a scope(exit) statement:

  {
    <statements1>
    scope(exit) statement<2>
    <statements3>
  }

Let's pick the first scope in the block, so we can assume that <statements1> itself does not contain scope (but <statement2> and <statments3> might). Lowering transforms the code into this:

  {
    <statements1>
    try {
      <statements3>
    } finally {
      <statement2>
    }
  }

Following the transform, <statements3> and <statement2> are further lowered because they may contain additional scope statements. (The lowering always ends because the fragments are always strictly smaller than the initial sequence.) this means that code containing multiple scope(exit) statements is well defined, even in weird cases like scope(exit) scope(exit) scope(exit) writeln ("?"). In particular let's see what happens in the interesting case of two scope(exit) statements in the same block.

  }
    <statements1>
    scope(exit) <statement2>
    <statements3>
    scope(exit) <statement4>
    <statements5>
  }

Let's assume that all statements do not containing additional scope(exit) statements. After lowering we obtain

  {
    <statements1>
    try {
      <statements3>
      try {
        <statements5>
      } finally {
        <statement4>
      }
    } finally {
      <statement2>
    }
  }

The purpose of showing this unwieldly code is to figure out the order of execution of multiple scope(exit) statements in the same block. Following the flow shows that <statement4> gets executed before <statment2>. In general, scope(exit) statements execute in a stack, LIFO manner, the reverse of their order in the execution flow.

[/quote]

Only asserts or exceptions would/can manage to decide if the block was successful or not; And the scope(s) can then manage cleanup (or final code) regardless where it was put without you having to do it yourself. If there's never any chance of it failing in the function then scope may not be what you want.

However if compiler knows and can verify the code is unable to fail (thus exceptions are not needed) perhaps an enhancement request that could remove the unneeded try/catches...

Reply via email to