• Advertisement
Sign in to follow this  

The C++ "finally" keyword and its relation to design-by-contract

This topic is 3343 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've seen a few proposed systems to apply design-by-contract to C++. They're a bit verbose. It's obvious that common assertions at the beginning of a function are enough to express pre-conditions. Post-conditions, however, are much trickier. You can slap some assert()'s at the end of your function body, but you can't guarantee that a previous piece of code won't return earlier. Especially when re-visiting old code, you can just add a new return and not care/not remember that some post-conditions must always be verified. It's tedious work, and hard to maintain all those assertions. So there's a tight relationship between clean-up when exiting scope and asserting post-conditions. It would be cool if we could instruct the compiler to run some code on scope exit, no matter what happens. This would be solved with the proposed keyword "finally", which is available in VS but has to be used with a "try" block, making it very intrusive (ie, try {...} finally {...} ). It's also not available on other compilers (AFAIK). With this in mind, I set out to re-create the "finally" keyword myself. Using it in design-by-contract:
void f() {
	// pre-conditions:
	assert(...);
	// post-conditions:
	finally {
		assert(...);
		assert(...);
	}

	// main body
}
It's also useful for other kinds of clean-up, undoing actions on error, logging, etc. I managed to do it with a macro to create a local class that executes a block of code in its destructor. The main advantage of the macro is that you can access the scope of the original function, which a simple local class usually can't do. Without that feature the method would be rendered obsolete. It's a macro, and I know many people don't like those. But anyways, before posting the code I'd like to gauge interest in this. Would you find it useful? Is there a simpler alternative? Jotaf

Share this post


Link to post
Share on other sites
Advertisement
Why not use a function ? This way, no matter where you return from, you still assert post-conditions:

private: void do_foo() { /* Code here */ }
public: void foo() { assert(pre); do_foo(); assert(post); }


The problem with destructors is that you don't really want to check for post-conditions when you throw an exception: any conditions related to "I will return the right data" are obviously incorrect when an exception is thrown, and any conditions related to the class state are either incorrect (an exception happened because they couldn't become true) or obviously correct (the exception rolled back any modifications to restore the initial state).

Share this post


Link to post
Share on other sites
Quick response! :)

That's a viable solution, but it suffers from the maintainability problem of other alternatives. You'll need to work hard to have a duplicate of every function in your program -- not to mention name clashes. It's something I didn't think of and I'm glad you mentioned it, attempting to streamline its use might be worth a shot.

I see where you're getting at with the destructors, but it doesn't seem an issue with other systems. To name a few:
Using Design by Contract in C by Charlie Mills
Design by Contract Framework for C++ By Kevin McFarlane
Design by Contract in C++ By Jarl Lindrud

The first one involves a pre-processing perl script, but the other two simply use local classes and destructors like I'm proposing. (Their methods don't allow such freedom to define any assertion you want, though.) They simply ignore the issue you raised. Of course, just because someone else is doing so is no excuse. But from my experience, it doesn't really matter if some code throws, thereby causing another one to throw; it's what happens commonly with a lot of errors anyway.

Share this post


Link to post
Share on other sites
This could also be useful in C, to do the free-ing of allocated memory at the end of a function!

Share this post


Link to post
Share on other sites
Or in other words, Digital Mars D has this feature too.

Still, it's a really nifty feature and it's too bad that g++ doesn't have it. ( Or atleast, not that I know of. And if this is the case, then it really lacks documentation on the net in my opinion. )

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
The problem with destructors is that you don't really want to check for post-conditions when you throw an exception: any conditions related to "I will return the right data" are obviously incorrect when an exception is thrown, and any conditions related to the class state are either incorrect (an exception happened because they couldn't become true) or obviously correct (the exception rolled back any modifications to restore the initial state).
The method of using a destructor isn't totally without merrit though. It can still be used to verify the internal state of the class upon exit, if you're aiming for writing methods with strong exception guarantees.
It will also work fine for methods that cannot throw exceptions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jotaf
With this in mind, I set out to re-create the "finally" keyword myself.


Your "finally" has different semantics than the normal usage -- when execution reaches the finally block, it only registers actions to be done later, rather than occurring immediately. I'd name it something else. Maybe POSTCONDITIONS ? (lowercase #defines are evil! EVIL!)

The dangers of possibly throwing from a destructor have already been noted, yes?

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
It will also work fine for methods that cannot throw exceptions.


That's the idea. I'll probably have two versions. The first one is intended for cleaning-up code (Finally), and as you probably expect behaves exactly like a destructor. As the C++ Standard has it, it will terminate the process if a 2nd exception is found. Here's a nice discussion on the subject (and the reasoning behind throwing destructors).

The second version (PostConditions) only runs when an exception was not already thrown (by checking std::uncaught_exception()). So it's only intended to run in the event of a return statement. Here's where you can have some asserts() for your post-conditions. It's more general than that, can someone suggest a new name?


Quote:
Original post by MaulingMonkey
I'd name it something else. Maybe POSTCONDITIONS ? (lowercase #defines are evil! EVIL!)


Weird, I find that UPPERCASE in the middle of well-formed code hurts my eyes so if this is going to be of any general usage, it could be LikeThis. Of course it'd be better to leave it as a choice to the programmer-user. Not enough libraries give you that kind of choice :)


Quote:
The dangers of possibly throwing from a destructor have already been noted, yes?


Ah yes, the old problem with throwing destructors. I hope the addition of std::uncaught_exception() mentioned above is enough to avoid that, and the link might provide you with some insight on the whole subject.

Share this post


Link to post
Share on other sites
Quote:
Original post by Lode
This could also be useful in C, to do the free-ing of allocated memory at the end of a function!


Unfortunately this uses local classes so it's not really for C. I see where you're coming from though.

Quote:
PinguinDude
Or in other words, Digital Mars D has this feature too.

Still, it's a really nifty feature and it's too bad that g++ doesn't have it. ( Or atleast, not that I know of. And if this is the case, then it really lacks documentation on the net in my opinion. )


It's too bad that it isn't in C++ already! It would allow for much better error handling and come handy in many other situations as well. Unfortunately C++ makes it really difficult to delay code execution of any kind. I've been looking at boost::lambda (and even saw a DBC implementation that used it) but it's not the same thing.

Share this post


Link to post
Share on other sites
If you need to replicate a finally block as in Java, there's two approaches which can be useful in different circumstances.

1) Using ScopeGuard, which is part of the Loki library.
2) You can replectate try-finally in C++ using the following idiom:


try
{
...
}
catch (...)
{
finally_code;
throw;
}

finally_code;



You can encompass this with a macro like this:


#define MY_FINALLY(X) catch(...) {X; throw; } X;



You can use it like this. Note the difference of using ( ) instead of { } for the "finally block". This will prevent you from being able to use , as a statement that isn't encompassed by nested parenthesis, but this has rarely been an issue in practice.


try
{
...
}
MY_FINALLY
(
finally_code;
)



Although I usually advocate avoiding macros as much as anyone, weighing that against code duplication is a no brainer.

One other thought on your specific question, though. If you think about, post conditions have automatically been violated if you throw an exception out of a function. So, personally, I would either avoid the asserts when an exception is thrown, or at best, simply use the asserts to guarantee one of the exception guarantees in this case, because some other expected post-conditions may not make sense in the presence of an exception.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rydinare
If you need to replicate a finally block as in Java, there's two approaches which can be useful in different circumstances.

1) Using ScopeGuard, which is part of the Loki library.


I've seen it, it's ok. But it suffers from being too verbose, and it limites you to extremely simple operations. For example:


void Decrement(int& x) {
--x;
}

void UseResource(int refCount) {
++refCount;
ScopeGuard guard = MakeGuard(Decrement, refCount);
...
}





Instead of this:


void UseResource(int refCount) {
++refCount;
Finally {
--refCount;
}
...
}




Can you see how theirs doesn't scale well with code complexity? You'll have to define a dummy function for every little operation you want to do. Otherwise you're stuck with a limited set of one-liners.

But yes, I respect ScopeGuard and if I didn't have a choice it's the one I'd probably use.

Quote:
2) You can replectate try-finally in C++ using the following idiom:

*** Source Snippet Removed ***


Unfortunately, you still need to duplicate "finally_code" at every return statement. It's a serious penalty for any sizable project.

Quote:
So, personally, I would either avoid the asserts when an exception is thrown...


That's possible with the standard function uncaught_exception() I mentioned.

I'll post back when I got this thing working, probably later today (I've got other stuff to do too :) ).

Share this post


Link to post
Share on other sites
To be honest, I never found the point of adding postconditions.
Preconditions are useful because you can be provided with bad input, and so it might be useful to detect such input; but postconditions are only dependent on your own code, which should always be correct whatever the correct input.

Also, the reason why there is no finally keyword in C++ is because it is intended that you use destructors instead, which are way less verbose if you model your objects correctly.

Share this post


Link to post
Share on other sites
Quote:
Original post by loufoque
but postconditions are only dependent on your own code, which should always be correct whatever the correct input.


So you can guarantee that all of your code returns correct output all of the time? You must be a hell of a programmer then ;)

Quote:
Also, the reason why there is no finally keyword in C++ is because it is intended that you use destructors instead, which are way less verbose if you model your objects correctly.


I can't see how the simple existence of well-defined objects prevents a function from returning bad output. Bad output is more than just ill-formed objects.

Don't mean to come out too harshly but my engineering background tells me that all systems fail and the more assumptions you make, the badder it will crash. A program being maintained is always subject to human error.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jotaf
Can you see how theirs doesn't scale well with code complexity? You'll have to define a dummy function for every little operation you want to do. Otherwise you're stuck with a limited set of one-liners.

But yes, I respect ScopeGuard and if I didn't have a choice it's the one I'd probably use.


I definitely agree. I usually only use ScopeGuard if I can reuse the extra function that goes in the ScopeGuard. Otherwise I opt for option #2 with the macro I mentioned earlier.

Quote:
Original post by Jotaf
Unfortunately, you still need to duplicate "finally_code" at every return statement. It's a serious penalty for any sizable project.


When you say serious penalty, what are you referring to? Code size? Performance? The macro I suggested removes the duplication from the maintenance point of view, although technically the code will exist twice. If it's an optimization related issue, you still have the option of moving that "finally_code" into another function if you find it's a performance bottleneck. Since you're intending to use asserts, that code actually won't exist in release anyway. If you're using just asserts, you could take it a step further and macro out the try-finally block as well. But, again, I do advocate being cautious of overuse of macros.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jotaf
... the more assumptions you make, the badder it will crash. A program being maintained is always subject to human error.
There's a flipside to that though. The fewer assumptions you make, the more code you have to write and the more code you have, the more bugs you have (on average). "Dammned if you do, damned if you don't", if you will. The best way is to document assumptions either in the form of a runtime assert or a compile-time C_ASSERT.

And yes human error is alive and kicking - keeps websites like www.thedailywtf.com alive.

Share this post


Link to post
Share on other sites
Quote:
So you can guarantee that all of your code returns correct output all of the time? You must be a hell of a programmer then ;)

Yes, I can infer whether a simple constant-time relation is true after a page of code.
If I can't, it means the code must be rewritten.

Quote:
I can't see how the simple existence of well-defined objects prevents a function from returning bad output. Bad output is more than just ill-formed objects.

How is that even related to finally?
Finally is a mechanism to perform cleanup, be it in face of exceptions or not. The mechanism recommended to do that in C++ is destructors.
It does require modeling your objects so that there is a destructor that does what you want.

For example, instead of writing
void UseResource(int refCount) {
++refCount;
try
{
...
}
finally {
--refCount;
}
}

You write
void UseResource(resource_ptr res) {
...
}

Share this post


Link to post
Share on other sites
There's always goto. A couple goto's to a single "end" label doesn't strike me as too heinous.

As for my other off-hand idea: I think the term I'm looking for is a closure: a locally defined function that has access to the functions' local variables. You could define a closure that does all your cleanup and post-condition stuff. The only problem is that you can't return from the whole function that way. So you have your finally function, then return; everytime you want to kill the function. Two lines of code. Better IMHO than macro based evilness.

Can't you fake closures with local classes, or something like that?

Share this post


Link to post
Share on other sites
Quote:
Original post by loufoque
To be honest, I never found the point of adding postconditions.
Preconditions are useful because you can be provided with bad input, and so it might be useful to detect such input; but postconditions are only dependent on your own code, which should always be correct whatever the correct input.


Preconditions and postconditions have different objectives. As you mentioned, preconditions are useful because they document and enforce the expectations and assumptions that a piece of code has over its environment. By contrast, postconditions document and enforce the assumptions that the environment has over the piece of code.

You can't determine whether your code is correct without knowing what it's expected to do. Of course, when you're writing a function, what your code should be doing is obvious because you've just designed the function. But a few months along the line, the only thing you have left is your code and your function name—enough to guess what the function does, but not accurately enough to make out which details of your code are accidental and which are actually expected to happen.

Share this post


Link to post
Share on other sites
Quote:
Can't you fake closures with local classes, or something like that?

Closures in C++ are known are functors.
See Boost.Phoenix, Boost.Lambda, etc. for generating functors in line with a simple Domain-Specific Embedded Language.

Share this post


Link to post
Share on other sites
Quote:
Original post by Rydinare
Quote:
Original post by Jotaf
Unfortunately, you still need to duplicate "finally_code" at every return statement. It's a serious penalty for any sizable project.


When you say serious penalty, what are you referring to? Code size? Performance?


Sorry, I wasn't complaining about either of those. I meant that since many functions have decision paths that return early, you'd need to duplicate that code at every return statement.

Quote:
Original post by loufoque
void UseResource(resource_ptr res) {
...
}


Yes but at the end of the day, are you really using that for every single aspect of your program? It's impractical.

Quote:
Closures in C++ are known are functors.
See Boost.Phoenix, Boost.Lambda, etc. for generating functors in line with a simple Domain-Specific Embedded Language.


That one I'll buy. It's been done before, with a reported "noticeable increase in compilation time" and "The runtime penalty is also significant". We need to aim for a more lightweight solution.

Quote:
Original post by theOcelot
There's always goto. A couple goto's to a single "end" label doesn't strike me as too heinous.


That would mean to replace every return with a goto. It's not that bad, really, but everyone who saw it would be left scratching their heads wondering "what the...?" :) You don't need to defend this solution with me, but you would with 9 out of every 10 programmers who work with you.

Quote:
Can't you fake closures with local classes, or something like that?


Right, that's what I'm doing :)

ToohrVyk: Couldn't agree more!

Share this post


Link to post
Share on other sites
Here's the current state of affairs for you guys to dissect. Each macro will expand into the following:


struct OnExit{
int &i;
OnExit(int &i_) : i(i_) {};
~OnExit() { if (!std::uncaught_exception()) { some-code } };
} onexit(i);

struct OnError{
int &i;
OnError(int &i_) : i(i_) {};
~OnError() { if (std::uncaught_exception()) { some-code } };
} onerror(i);

struct OnExitOrError{
int &i;
OnExitOrError(int &i_) : i(i_) {};
~OnExitOrError() { some-code };
} onexitorerror(i);




This is a local class by the way. The "i" parameter in the constructor is a local variable that you wanna test in the "some-code" part -- there is no other way to access the caller's context. So you'd need to repeat that pattern for a number of variables that you want to use. The storage type (in this case int) must also be specified. It seems that templates aren't legal in local classes, which is a shame.

Anyways, the really neat thing is that as long as the internal references to the local variables have the same names as said local variables, you can just take some code that used to be in the original function, put it inside the local class unchanged and it just works.

The macros are supposed to replicate that up to a certain number of parameters, let you specify the local vars and their types, and also give each instance a different name to prevent conflicts in case you use several of these.

Feel free to punch a whole through it though :)
I'm not so sure about the names (OnExit is where you're supposed to put your assert()'s), and maybe there are some cases I forgot where this will not work.

EDIT
It works now, I just need to find a place to post it up. Example usage:


double my_sqrt(double x) {
double res;

// pre-conditions:
assert( x > 0 );

// post-conditions:
OnExit2(double,x, double,res, {

assert( res * res == x );

});

// main function body
res = sqrt(x);

// uncomment the following line to crash this thing
// (post-condition won't verify)
//res++;

return res;
}

void main() {
cout<<"Sqrt(30)="<<my_sqrt(30);
}



[Edited by - Jotaf on December 22, 2008 7:54:48 PM]

Share this post


Link to post
Share on other sites
could your solution possibly lay with AspectC++?

If all you want is pre-post assertions then maybe you could write a quick processing tool which could do some trivial source-to-source translation before you run your compilation, it wouldn't significantly change how you would do things so long as the source code was written out to a new location, then debugging wouldn't be affected.

The nice thing about this approach is that you can turn it off when you go to release mode, and the runtime and compile time overhead is minimal, and yes there will be a maintenance burden, but I think it may be less than inline Macros everywhere in your code?

some examples to get your mind working:

struct my_doofer {

int doofer(int x, int y) {
//!pre x<10
//!pre y>10
//!returns x+y

return x+y+1;
}
};





and your command line too would process the file and produce something like this:

struct my_doofer {
/**generated method: unprocessed method name was: int doofer(int,int) */
int doofer_checked__(int x, int y) {
return x+y+1; /*original source line: 8*/
}
int doofer(int x, int y) {
/*precondition*/ assert(x<10);
/*precondition*/ assert(y>10);
int returns = doofer_checked__(x, y);
/*postcondition*/ assert(returns == x+y);
return returns;
}
}





IMO this would be very simple to write using Python or even C if you feel up to it, and I think it would meet your requirements nicely.

I have thought a few times about implementing a simple "Java Annotations" style system like this, for reasons not dissimilar to yours.

Cheers,
-Danu

[EDIT: also, the original source code doesnt get convoluted and the syntax for the pre and post conditions is nice and tidy and pretty easy to appreciate, even to new commrs to your code.]

Share this post


Link to post
Share on other sites
Quote:
"The runtime penalty is also significant"

If there is, then either your compiler has serious problems or you didn't enable optimizations.
Or maybe you didn't realize what a functor was and always put them in boost::function (which is a polymorphic functor container, which of course adds overhead).

Anyway, in the next C++ standard there is support in the language for defining closures inline.

Quote:
Yes but at the end of the day, are you really using that for every single aspect of your program? It's impractical.

Yes, I do. (I would even consider code that doesn't to be garbage, but I'm quite the extremist)
It's not impractical if you know how to do it right. It also guarantees at least basic exception-safety throughout your whole program.

Share this post


Link to post
Share on other sites
Quote:
Original post by Jotaf
Yes but at the end of the day, are you really using that for every single aspect of your program? It's impractical.
It's known as RAII, and is generally considered to be the "best practice" in C++ as far as handling resource release is concerned.

The premise of RAII is simple: whenever you have a manipulation that has to be done in two separated steps (be it alloc-dealloc, increment-decrement, lock-unlock, open-close, start-finish or whatever else you can imagine) you wrap the first step in a constructor and the second step in a destructor. Consider that:
  • You don't have that many two-step operations to handle.
  • All of the two-step operations in C++ are already handled for you this way by the standard library.
  • Once the operation is wrapped, the "constructor calls member constructor, destructor calls member destructor" principle in C++ means you don't have to wrap things more than once and so 99% of your code relies on RAII implemented by 1% of your code without additional work.
  • You even have specific wrappers provided by boost to operate on a certain resource with a certain function at end of scope (or when the last shared reference is destroyed), so it's often a matter of boost::shared_ptr<Obj> obj(Frobnicate(), UnFrobnicate);


In the end, the "wrap once, reuse everywhere" approach seems, at least to me, more appealing than the "use 'finally' everywhere", and is quite possibly the reason C# introduced the 'using' keyword to avoid the 'finally' infestations of Java.

Share this post


Link to post
Share on other sites
Over-use of any concept can be harmful, but I've found that the R in RAII can often be a deterrent to adoption, since it implies there is some physical or external resource that is being managed.

But combined with strong typing, RAII methodology can be surprisingly powerful. A trivial example:
struct rect {
rect(int x1, int y1, int x2, int y2) {
assert(x1 < x2);
assert(y1 < y2);
}
private:
};
There is no "resource" here, it's just a bunch of ints. But the implications of RAII lead to several benefits.

Constructor asserts the contract. A rect instance cannot be created unless it passes those tests. So by implication, foo(rect) operates on valid rect. Obviously, this may seem like an overkill at glance, or perhaps a complication. But once carefully examined, writing robust code simply requires these assertions, and nothing less. So whether they're present as unit test or as design-by-contract, they cannot be avoided - might as well use the most natural mechanism already provided by language.


Of course, once an instance is constructed, non-const methods may corrupt internal state. Both C# and Java make extensive use of immutable types. In general, immutable types (in C++ created through RAII) make it considerably simpler to maintain. In some ways, they represent invariants.


Obviously, nothing is ever that easy, so eventually one does need non-const member functions, which is where formal testing comes into play. But IMHO, use of RAII coupled with consistent and properly implemented rule-of-three goes a very long way towards eliminating whole classes of bugs present in C++.

However, to get the benefit of such approach, classes should be auto-allocated. Various smart pointers count as such too.


An interesting side-effect of strict RAII/immutable enforcement is that code starts looking more like functional language. And I'm not sure that's a bad thing...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement