
2012/8/30 Lorenzo Caminiti <lorcaminiti@gmail.com>
On Wed, Aug 29, 2012 at 2:48 PM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
I believe the community needs BbC framework: it is necessary in order to be able to program consciously.
I personally agree, that's why I start the documentation with the quote:
“Our field needs more formality, but the profession has not realized it yet.” --Meyer (see [Meyer97] page 400)
However, my impression is that the general C++ community is more on the "profession" side ;)
This is my impression also...
you cannot use some C++ constructs that you would otherwise use;
Like, for example? (Because I made a conscious effort to support "all" C++ declaration features in the DSEL, if at all possible...) I know of function pointers, arrays, member initializers in deferred implementations but there are workaround for those. Anything else?
Indeed, the support for C++03 declaration is satisfactory. When i wrote it I mostly meant the limitation where "when member initializers are specified, the constructor body must be defined together with its declaration and contract". Apart from this and array or function types I did not think of anything else. But now, that I think of it, I wonder how vendor-speciffic extensions are (or could be) supported, like Microsoft's __declspec? While they are not C++-standard I must use them when implementing a DLL.
(13) The documentation says that you can use protected and private members in contracts because "C++ provides programmers ways around access level restrictions (e.g., friend and function pointers)". Next, we read that "only public member functions shall check class invariants. Private and protected member functions are allowed to brake class invariants because private and protected member are part of the class implementation and not of its specification".
This 2nd statement is correct. The 1st statement means that in C++ you can never prevent people from programming junk like this which will break the public interface (the same can be done without static):
#include <iostream>
class x { public: static void pub ( void ) { std::cout << "pub" << std::endl; } private: static void priv ( void ) { std::cout << "priv" << std::endl; }
typedef void (*fptr) ( void ); public: static fptr bad ( void ) { return priv; } };
int main ( void ) { x::pub(); void (*priv) ( void ) = x::bad(); priv(); // calls a private function :( return 0; };
The call to priv via the function pointer is done outside the class implementation but it won't check the invariants--but if you program "bad" then you're on your own! That's all I wanted to say with the 1st statement (which is actually an observation from The C++ Programming Language, Stroustrup). I can clarify this in the docs.
I feel I have been misunderstood. Let me clarify. I understand how one can overcame the member access restrictions in C++ with hacks. I do not think you need to clarify it in the docs. The way I understand the docs is that you use these hacks as rationale for allowing private and protected members in contracts. Or in other words, that you chose to allow private members in contracts only because "member access hacks" are possible. I think that this rationale is too week. Personally, I feel that I would rather have only public members allowed in contract specifications. I could be convinced otherwise, but I find the above argument unconvincing.
(16) Functions like set_precondition_broken() are defined with dynamic exception specification: throw(). Is this necessary? throw() is known to be causing problems, adds little value, and some compilers do not support it; some other issue warnings on dynamic exception specifications; and they are deprecated.
It's the same for set_terminate that is throw() and it was specified by N1962:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#failure-h...
I think you don't want the handler setting function to throw given that what you are setting is the handler itself which will affect how you will handle a thrown exception (e.g., while evaluating a contract assertion).
I agree that this function had better not throw. But... You implement this function: you can implement it so that it does not throw and guarantee that in the documentation, but you need not use "throw()" syntax. By typing "throw()" your implementation does not throw less. But you can make the function execute slower because now the run-time will also have to check if your function throws (you know it doesn't - but the compiler or run-time does not) and if so, call std::unexpected(), and so on... I understand than n1962 proposes it, but dynamic exception specifications were not deprecated at the time it was proposed. Now it would probably be proposed as noexcept(true). Also, see this Boost guideline http://www.boost.org/development/requirements.html#Exception-specification.
(20) In "Contract Programming Overview" -> "Benefits", in the note we read, "However, the probability that programmers make a mistake twice (in both the body *and* the contract) is lower than the probability that the mistake is made just once (in either the body or the contract)". This implies that we write contracts in order that the code be duplicated because this reduces the probability of the bug. I believe that the mechanism of testing in general is somewhat different (contract-checking is similar to unit testing in this respect, I think): you want the tests to be much simpler then the code they test.
No, this is just about probabilities. Say p is the probability to program a bug in the body and q the probability to program a bug in the contracts for a given function. Le'ts assume independence of the events for programming a bug in the implementation and programming a bug in the contracts for that function. Then the probably r of programming a bug in both the implementation and the contracts of that function is given by the product r = p * q. Given that p < 1 and q < 1 then r < p and r < q. This doesn't assume you duplicate code, it's just that if you do two things independently it's less likely you mess both of them up :) See Section 3.6 of N1613: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2004/n1613.pdf
Well, I am unconvinced. I understand the argumentation in N1613 but I do not feel this is a practical value gained from contracts. Using the probabilistic notions, I question the validity of the assumption that p and q are independent. But I am not trying to convince you. Just expressing my 'feeling'.
Therefore when some test fails you know (although not for sure) that it is the code that is broken rather than the test. For instance:
double sqrt(double v) postcondition{ close(return * return = v); };
Testing almost the same thing as function body makes sense because multiplication is conceptually much simpler than the logic to find the square root. Conversely, writing this:
bool invert(bool b) postcondition{ b == !return; };
Would be of little practical value, and I believe if there is a chance I
No, contract programming would ask you to leave the b == !return postcondition (Meyer is pretty clear about this). Of course you can do whatever you want but when you write the contracts you don't know about the implementation (e.g., a complex inversion algorithm that does some optimized assembly bit operation could be used by the body but the post still wants b == !return at the end of the day).
This is theoretically convincing, but I cannot imagine using such principle in practice. I would never think of implementing 'invert' in any other way than '!v'. And since it is so simple I would likely make it an inline function: bool invert(bool b) postcondition{ b == !return; } { return !v; } And I would not be comfortable encouraging my colleagues to write inline functions like this. And using the probabilistic argument for rationale. Again, I do not want to discourage anyone from specifying contracts. But I somehow feel Contract Programming offers more important benefits than the above probability. Regards, 7rzej