How to do conditional scope(exit) ?
Jonathan M Davis
newsgroup.d at jmdavisprog.com
Thu Dec 19 00:24:41 UTC 2024
On Wednesday, December 18, 2024 3:16:45 PM MST John Dougan via Digitalmars-d-learn wrote:
> As the subject. The obvious way:
>
> ```D
> import std;
>
> int test(int val)
> {
> writeln("A");
> if (val % 2 == 0)
> {
> writeln("b");
> scope (exit)
> writeln("scope exit ", val);
> writeln("c");
> }
> writeln("F");
> return 2 * val;
> }
>
> void main()
> {
> writeln("== start =========================");
> int v1 = test(1);
> writeln("== 2 ==============================");
> int v2 = test(2);
> writeln("== end ===========================");
> }
> ```
> results in:
>
> ```
> == start =========================
> A
> F
> == 2 ==============================
> A
> b
> c
> scope exit 2
> F
> == end ===========================
> ```
>
> which isn't what I want. The case for `test(1)` is fine. For
> `test(2))` I want the `scope exit 2` to come after the `F`. Is
> there a way to tell it that I want to use an enclosing scope or
> make it ignore the scope on the `if`?
scope statements are run when the scope that they're in exits (with
scope(exit) always running, scope(failure) running only when the scope is
exited via an exception being thrown, and scope(success) only being run when
no exception is thrown). There is no way to control whether they run beyond
whether it's exit, failure, or success, and trying to insert if statements
around scope statements is just going to change which scope that they refer
to, since you can't put a scope statement in an inner scope and then have it
be run for an outer scope. It's always for the scope that the scope
statement is in.
Now, you _can_ put an if statement within the scope statement to control
what's run within the scope statement, but that condition will be checked
when the scope statement is run. So, you may be able to get what you want
that way, but scope statements themselves are quite simple and not
particularly flexible. Ultimately, they're just a way to not have to
manually write a try-catch block when you don't care about actually looking
at the exception being thrown and just want to write code that runs or
doesn't run based on whether the scope is exited normally or via an
exception being thrown.
One thing to remember is that scope statements are implemented as try-catch
blocks. So, if you have something like
{
scope(exit) doStuff();
runCode();
}
it'll be lowered to something along the lines of
{
try
{
runCode();
doStuff();
}
catch(Exception e)
{
doStuff();
throw e;
}
}
and
{
scope(failure) doStuff();
runCode();
}
will be lowered to something like
{
try
{
runCode();
}
catch(Exception e)
{
doStuff();
throw e;
}
}
whereas
{
scope(success) doStuff();
runCode();
}
will be lowered to something like
{
runCode();
doStuff();
}
So, when you're considering what can or can't be done with scope statements,
thinking about how they're lowered to try-catch blocks may help you
understand why they work the way that they do. And if you can't do what you
want to do with a try-catch block, then you definitely can't do it with
scope statements, since that's what they ultimately are.
- Jonathan M Davis
More information about the Digitalmars-d-learn
mailing list