| |
| Posted by Jonathan M Davis in reply to John Dougan | PermalinkReply |
|
Jonathan M Davis
Posted in reply to John Dougan
| 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
|