May 12, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly wrote: > Ben Hinkle wrote: > >> "Stewart Gordon" <smjg_1998@yahoo.com> wrote in message news:e3vkhn$1kq5$1@digitaldaemon.com... >> >>> James Dunne wrote: >>> <snip> >>> >>>> Then the implementation according to D's language specs is incorrect. Nothing is mentioned about new scopes created by if-statements or while-statements. New scopes are only created from block { } statements when inside a function body. Scope is mentioned (in passing) for the for-statement; the initializer is noted as a special case. Did I miss a blanket statement somewhere else in the docs about this? >>> >>> I think you're meant to use a bit of common sense here. What sense does it make for a declaration to be conditional at runtime? >>> >>> To be honest, I think a naked declaration as the body of a runtime control statement should be illegal. >> >> >> You're probably right. I had tried dmc and cl and they both complained about the use of 'a' without a declaration but in fact I was expecting an error that a declaration can't be the body of an 'if' statement. Since both compiler didn't say boo about the declaration I figured that declarations are considered statements. The C99 spec doesn't consider a declaration a statement so I suspect the compilers are giving poor errors. > > > What about this: > > if( auto i = doSomething() ) > printError( i ); > > I don't think anyone would expect 'i' to survive after the printError expression. > > > Sean Straight from the docs: "If an auto Identifier is provided, it is declared and initialized to the value and type of the Expression. Its scope extends from when it is initialized to the end of the ThenStatement." It's buried in there that an implicit scope is created for these cases, but nothing whatsoever is said about scope for a straight "if (expression) not-block-statement". As you noted earlier, this is a corner case where one would expect a declaration-statement to be illegal as an if-statement's body. Declaration-statements really aren't statements, they're just parsed that way to alleviate complexity. -- Regards, James Dunne |
May 12, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stewart Gordon | Stewart Gordon wrote: > <snip> > > To be honest, I think a naked declaration as the body of a runtime control statement should be illegal. > You just reminded me of a feature of a language called Nemerle (which is a functional superset of C#): it has three conditional statements: if ... else ... where ... unless ... The thing here is that if you use "if", you must also have an "else" clause. "where" and "unless" are equivalent to "if(cond) ..." and "if(!cond) ..." in D. The rationale behind this is that it solves the problem of ambiguous chains of if/else. I actually always liked this, but am yet to see it in any other language. Speaking of neat stuff Nemerle does: "var" for type inference and immutable variables ;) -- Daniel -- v1sw5+8Yhw5ln4+5pr6OFma8u6+7Lw4Tm6+7l6+7D a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/ |
May 12, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ben Hinkle | Ben Hinkle wrote:
> I hope this doesn't come of as a flame, but I'm wondering if anyone is using scope(success) and why. I can't find any reason for it.
>
> Some background: I've slowed my D work to focus on some C experimental features I'm calling Cx: http://www.tinycx.org and currently I'm implementing the error handling using reserved labels "error:" and "finally:". The error label is roughly like scope(failure) and the finally label is roughly like scope(exit). There's no try-catch-finally. I don't plan on adding anything like scope(success) because I couldn't think of why anyone would want to use it. Why not just put the code at the end of the scope like normal code-flow? I suppose one could code the entire scope in reverse just for kicks:
> void main() {
> scope(success) printf("world\n");
> scope(success) printf("hello ");
> }
The scope(success) will execute even if the scope is exited via a return, break, or continue statement, but not if it is exited via a thrown exception. Thus, it is fundamentally different from just putting the code at the closing }.
The code:
{
foo();
scope(success) bar();
def();
}
is equivalent to:
{
foo();
int x;
try
{
x = 0;
def();
}
catch (Object o)
{
x = 1;
throw o;
}
finally
{
if (x == 0)
bar();
}
}
which is a tedious, error-prone, and unobvious thing to write.
|
May 12, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Serg Kovrov | Serg Kovrov wrote:
> In this particular case I don't want rollback on returning false, just if a db operation failed. And exceptions handle that rather well.
>
> My point is, if case is a bit more complicated then a 'hello world' example, there most likely will be different error conditions, and they meant be handled differently. Exceptions are convenient way to do it.
Exceptions work well as long as there is only one operation that needs to be rolled back. As soon as you have two or more operations that happen sequentially, and either both must succeed or neither, that the traditional exception mechanism starts coming unglued.
For example, if I have operations A(), B(), and C(), and A.rollback(), B.rollback() and C.rollback:
A();
scope(failure) A.rollback();
B();
scope(failure) B.rollback();
C();
scope(failure) C.rollback();
Just for fun, try to do that with either C++ exceptions or Java try-finally.
|
May 12, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote:
> When the "do cairo stuff" is just a simple function call, I don't really
> gain anything. But it comes in handy when I've got to return values
> from cairo functions, or when I have to use any kind of complex logic.
>
> Plus, I find reading "scope(success) checkStatus()" to be very clear;
> that, and it's immediately obvious just looking at the code if I've
> forgotten it (almost every function in the binding follows that pattern
> so exceptions to that are easily spotted).
Right. It eliminates the all-too-common bug of adding an extra return statement but forgetting to add the check/cleanup code that goes along with it.
|
May 13, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | In article <e42jr6$2u07$1@digitaldaemon.com>, Walter Bright says... > >For example, if I have operations A(), B(), and C(), and A.rollback(), B.rollback() and C.rollback: > > A(); > scope(failure) A.rollback(); > B(); > scope(failure) B.rollback(); > C(); > scope(failure) C.rollback(); > >Just for fun, try to do that with either C++ exceptions or Java try-finally. Off the top of my head... struct A // ditto for B and C { A() { doA(); } ~A() { if (std::uncaught_exception()) { rollbackA(); } } }; A a; B b; C c; I'm sure there are drawbacks; there always are. It's horses for courses. If the operations are common ones, the C++ approach wins out IMHO because you don't have to remember the scope statement (which is still a "wrong by default" design). If the operation is an ad-hoc one and you have to write the wrapper class yourself, the D approach is much cleaner since it keeps everything together and clarifies the intent. (Just look how popular std::for_each isn't.) cheers Mike |
May 13, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Capp | Mike Capp wrote:
> In article <e42jr6$2u07$1@digitaldaemon.com>, Walter Bright says...
>> For example, if I have operations A(), B(), and C(), and A.rollback(), B.rollback() and C.rollback:
>>
>> A();
>> scope(failure) A.rollback();
>> B();
>> scope(failure) B.rollback();
>> C();
>> scope(failure) C.rollback();
>>
>> Just for fun, try to do that with either C++ exceptions or Java try-finally.
>
> Off the top of my head...
>
> struct A // ditto for B and C
> {
> A() { doA(); }
> ~A() { if (std::uncaught_exception()) { rollbackA(); } }
> };
>
> A a;
> B b;
> C c;
This doesn't work because when the scope is done, no matter how it ends, A, B and C are *all* rolled back. The idea is that if the scope exits normally, A, B and C are *not* rolled back. The starting point for C++ would be:
A* a = new A();
B* b = new B();
C* c = new C();
I need all three to succeed or none. Think of something like a database transactions, where 3 different places in the database have to be updated as one operation. You can't leave it as 1 done, or 2 done. It has to be all 3, or none of them.
|
May 13, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Capp | Mike Capp wrote:
> In article <e42jr6$2u07$1@digitaldaemon.com>, Walter Bright says...
>> For example, if I have operations A(), B(), and C(), and A.rollback(), B.rollback() and C.rollback:
>>
>> A();
>> scope(failure) A.rollback();
>> B();
>> scope(failure) B.rollback();
>> C();
>> scope(failure) C.rollback();
>>
>> Just for fun, try to do that with either C++ exceptions or Java try-finally.
>
> Off the top of my head...
>
> struct A // ditto for B and C
> {
> A() { doA(); }
> ~A() { if (std::uncaught_exception()) { rollbackA(); } }
> };
It's probably a matter of implementation, but std::uncaught_exception isn't terribly useful in C++. The most obvious reason being that it acts globally rather than specific to the calling thread. I'm also not sure I like that the dtor would change behavior based on whether an exception is in flight. This results in unexpected behavior, which is never a good thing.
Sean
|
May 13, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | Walter Bright wrote:
> This doesn't work because when the scope is done, no matter how it ends, A, B and C are *all* rolled back.
Eh, I misinterpreted Mike's code. Sorry.
But the uncaught_exception doesn't do the job. It only gets invoked if some exception is uncaught anywhere on the call stack, not if it is just uncaught before the destructors are called.
|
May 15, 2006 Re: why scope(success)? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | In article <e45cvg$cib$2@digitaldaemon.com>, Walter Bright says... > >Walter Bright wrote: > >Eh, I misinterpreted Mike's code. Sorry. Quite all right. I misinterpret my code all the time. >But the uncaught_exception doesn't do the job. It only gets invoked if some exception is uncaught anywhere on the call stack, not if it is just uncaught before the destructors are called. Oops. I stand corrected. cheers Mike |
Copyright © 1999-2021 by the D Language Foundation