DMD 0.148 - scope guard
James Dunne
james.jdunne at gmail.com
Sun Feb 26 08:22:42 PST 2006
Kyle Furlong wrote:
> Dawid Ciężarkiewicz wrote:
>
>> Dawid Ciężarkiewicz wrote:
>>
>>> VERSION E:
>>> void LongFunction()
>>> {
>>> State save = UIElement.GetState();
>>> onscope {
>>> case success: UIElement.SetState(save);
>>> }
>>> onscope {
>>> case failure: UIElement.SetState(Failed(save));
>>> }
>>> ...lots of code...
>>> }
>>
>>
>> Just came to my mind:
>>
>> This version is especially neat because it may be simplified to:
>> void LongFunction()
>> {
>> State save = UIElement.GetState();
>> onscope {
>> case success: UIElement.SetState(save); break;
>> case failure: UIElement.SetState(Failed(save));
>> }
>> ...lots of code...
>> }
>
>
> I really like this idea, cons anyone?
I don't like the words 'success' and 'failure' used all over the place.
The meaning of the function's success isn't based on only if no
exceptions were thrown. Similarly, the function doesn't have to 'fail'
if an exception were thrown.
I think they should be renamed to represent what they actually do. That
is, 'no exception thrown'/'pass', 'exception thrown'/'catch', 'scope
exited'/'exit'. Also, I think it would be more pleasing to the eye (and
the maintainer) if the effect of the scope guard were more obvious in
the code. Something like:
void LongFunction()
{
scope (State save = UIElement.GetState())
catch {
UIElement.SetState(Failed(save));
}
pass {
UIElement.SetState(save);
}
body {
... lots of code ...
}
}
This way, it looks like a function contract, except it applies to any
scope. The catch block is reused but only for purposes of noting that
there was an exception caught. The pass block is quite simply the
'else' to the catch block, and should happen only if no exceptions were
caught. Furthermore, there could be a general 'exit' block.
One could add as many of these blocks as necessary, and the compiler
will guarantee to call them in order of definition, much like the
original solution but not requiring one to think backwards.
bool LongFunction()
{
bool passed = false;
scope (State save = UIElement.GetState())
catch { UIElement.SetState(Failed(save)); writef('0'); }
pass { UIElement.SetState(save); writef('1'); }
pass { passed = true; writef('2'); }
body {
... lots of code ...
}
exit { writef('3'); }
return passed;
}
So, if an exception were thrown in '... lots of code ...', you'd see
'03' and the function would return false. However, if no exception were
thrown you'd see '123' and the function would return true. This
demonstrates the order of execution across multiple blocks. In this
example, the order of the 'exit' block relative to the 'catch' and
'pass' blocks is important.
Consequently, I don't think the order of the 'body' block should matter
at all, relative to the other blocks; and it should be fixed to only
allow one instance of it. Then, it is a matter of personal/project
style where the 'body' block would fall.
Thoughts on this?
One last thought I had was to remove the parenthesized expression form
of scope (expr) ... and use another block name to represent the
initialization stage, just to be consistent.
--
Regards,
James Dunne
More information about the Digitalmars-d
mailing list