|
Boost : |
Subject: Re: [boost] [dbc] Interest in Design By Contract for C++?
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2009-10-24 13:22:12
Hello all,
<Thomas.Klimpel_at_[hidden]> wrote:
>> Lorenzo Caminiti wrote:
>> > *** To me, this is a key question for Boost programmers: IS THIS C++
>> > SYNTAX TOO FOREIGN LOOKING OR DIFFICULT TO USE TO BE ACCEPTABLE? ***
>
> Doesn't Boost.Parameter also uses a foreign looking syntax? But I admit that "DBC_MEM_FUN" is a bit cryptic. How about BOOST_DBC_MEMBER_FUNCTION?
Yes, as Thomas indicated, Boost.Parameter already uses a foreign
looking syntax. That essentially answers my question: While the
necessity to introduce a macro-based foreign looking syntax like the
one of this library should be carefully considered, I do not think
Boosters will reject it in principle.
SYNTAX
1) I knew of the existence of Boost.Parameter but I never used it so I
did not know its API. After Thomas' comment, I have studied
Boost.Parameter API and its documentation. The Boost.Parameter
macro-based foreign looking syntax is actually very similar to one of
this library: Boost.Preprocessor sequences are used to allow the
macros to generate function signatures with parameter names/types,
return types, etc; There is a BOOST_PARAMETER_MEMBER_FUNCTION,
BOOST_PARAMETER_CONSTRUCTOR, etc similarly to DBC_MEM_FUN,
DBC_CONSTRUCTOR, etc.
2) In addition, other Boost libraries like Boost.Test (great library
which I use every day) and Boost.TypeOf rely heavily on macros (even
if in a contexts different from the one of this library and
Boost.Parameter). Therefore, I think the use of macros (while always
best avoided), it is accepted by Boosters when necessary.
"The first rule about macros is: Don't use them unless you have to.
Almost every macro demonstrates a flow in the programming language, in
the program, or in the programmer.", The C++ Programming Language, B.
Stroustrup, 1997. This library uses macros to overcome a programming
language limitation extending C++ with DBC features. Languages like
Eiffel have built-in language support for DBC; Other programming
languages like Java and Ada use external pre-processing tools to
support DBC (but that's cheating...).
Gottlob Frege wrote:
> they are **domain-specific**
> This, for me at least, makes a big difference. I don't mind seeing
> some strangeness within a certain domain or to solve a particular
> problem. But when the augmented language is NOT domain-specific, and
> instead is used all over your code, then I start thinking that maybe
> we should just be using a different language.
3) I also understand the concern expressed by Tony that the "DSEL"
syntax of this library has a domain that extends to all your class
*declarations* (or at least to all the ones for which you need to
write contracts) -- that is a pretty large domain... I think, at the
end designers/programmers will have to judge if the complexity added
by the macro syntax is worth the benefits of DBC for their specific
application -- but using Eiffel instead of C++ might not be a
realistic option for some (most?) applications.
In addition, I would like to stress out that the foreign looking macro
syntax only applies to the class declarations and NOT to their
definitions -- therefore, only your .hpp files will contain the
foreign looking macros, while your .cpp files will essentially remain
unchanged.
NAMING
While my question above was not directly concerned with this library
current naming conventions, quite a few comments were made on naming.
I think that means that properly chosen names could help making the
macros less cryptic (even if they will still retain the foreign
looking preprocessor-sequence syntax). In general, I will be more than
happy to change the library names to fully comply with Boost
guidelines and to be as clear as possible to Boosters.
1) Yes, if this library were to become a Boost library, all macro
names will have to start with "BOOST_" (and all library code will have
to be included in the "boost::" namespace).
2) Yes, Boost usually fully spells all symbols so MEM_FUN should be
MEMBER_FUNCTION, and same story for any other symbol of this library
that is not fully spelled. (I try to only use abbreviations already
used by the STL, like MEM_FUN similar to the std::mem_fun binder but I
am also happy to fully spell all symbols.)
3) The "DBC_BASE(type)" and "DBC_COPYABLE(type)" macros could be
replaced by "(inherit)(type)" and "(copyable)(type)" if that made the
macro syntax more clear (this will then be similar to the keywords
"optional" and "required" introduced by the Boost.Parameter macro
syntax). With a bit more work in the library implementation, I think
it might be possible to remove the need for DBC_INHERIT_OBJECT and
DBC_MULTI_INHERIT_OBJECT (I will have to look at the details of
this...).
On Mon, Oct 19, 2009 at 7:59 AM, Paul A. Bristow
<pbristow_at_[hidden]> wrote:
> Acronymitis is a serious problem for me ;-(
> DBC_ everywhere just looks very nasty.
4) DBC (actually "DbC"(TM) to be precise, as indicated by Neil) is a
well recognize industry acronym for "Design by Contract"(TM). However,
there might be trademark concerns in using this acronym (see
http://en.wikipedia.org/wiki/Design_by_contract) and programmers have
been using Programming by Contracts (PbC) or Contract Programming (CP)
instead. The use of these other, much less know, acronyms will only
increase Paul's concern above... In my opinion, if DBC is not to be
used than "Contract" will be the best alternative.
NAMING OPTIONS
a) Use "DBC" (similar to Boost.MPL, Boost.CRC, etc)
Library: Boost.DBC
Namespace: boost::dbc
Macros: BOOST_DBC_CONSTRUCTOR, BOOST_DBC_DESTRUCTOR,
BOOST_DBC_MEMBER_FUNCTION, etc
b) Use "Contract" (similar to Boost.Parameter, Boost.Test, etc)
Library: Boost.Contract
Namespace: boost::contract
Macros: BOOST_CONTRACT_CONSTRUCTOR, BOOST_CONTRACT_DESTRUCTOR,
BOOST_CONTRACT_MEMBER_FUNCTION, etc
I am equally happy with either option a) or b).
EXAMPLE OF b)
This the NameList example I presented in a previous email reworked to
use naming convention b). It also shows that the foreign looking macro
syntax does NOT affect your .cpp files when function definitions are
separated from their declarations.
// File: RelaxedNameList.hpp (declarations with foreign looking macros).
#include <boost/contract.hpp> // This library, if added to Boost as in
option b).
class RelaxedNameList: public NameList
// Maybe the "..._INHERIT_OBJECT()" macros can be removed...
not sure yet.
BOOST_CONTRACT_MULTI_INHERIT_OBJECT(RelaxedNameList) {
public:
void put(const std::string& name)
BOOST_CONTRACT_MEMBER_FUNCTION( (public) (void)
// Using "copyable" and "inherit" instead of
"..._COPYABLE()" and "..._BASE()" macros.
(copyable)(RelaxedNameList) (inherit)(NameList) //
Subcontracting (inherit) from NameList::put.
(put)( (const std::string&)(name) ), {
// This preconditions (in OR with the base preconditions
allowing for duplicated names in the list).
BOOST_CONTRACT_ASSERT_STREAM(self.has(name), "in list",
err << "name '" << name << "' not in list");
}, {
// This postconditions (in AND with base postconditions).
if (self.old.has(name.now))
BOOST_CONTRACT_ASSERT(self.now.count() == self.old.count(),
"if in list, count unchanged");
}, ; /* Body: ";" to separate definition from declaration. */ )
...
private:
BOOST_CONTRACT_INVARIANT(RelaxedNameList, {
// Invariants (in AND with base invariants, no additional
invariant here).
})
};
// EOF
// File: RelaxedNameList.cpp (definitions, with NO foreign looking
macro a part from BOOST_CONTRACT_BODY).
#include "RelaxedNameList.hpp"
void RelaxedNameList::BOOST_CONTRACT_BODY(put)(const std::string& name) {
... // This function implementation.
}
...
// EOF
Thank you all for your comments so far. I will follow up with a couple
of more technical emails illustrating some of the library internal
mechanisms and comparing this library with DBC support from other
languages, libraries, and proposals.
Cheers,
Lorenzo
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk