Boost logo

Boost :

Subject: Re: [boost] [Review:Contract] Some questions
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-08-26 20:55:17


On Sun, Aug 26, 2012 at 10:00 AM, Vicente J. Botet Escriba
<vicente.botet_at_[hidden]> wrote:
> Le 26/08/12 18:24, Lorenzo Caminiti a écrit :
>
>> Hi,
>>
>> On Sun, Aug 26, 2012 at 2:16 AM, Vicente J. Botet Escriba
>> <vicente.botet_at_[hidden]> wrote:
>>>
>>> Hi,
>>>
>>>
>>> First of all, thanks Lorenzo for your work on pre-processor programming.
>>> With this library, you have showed to me how far the pre-processing can
>>> go
>>> in terms of expressiveness.
>>
>> Welcome :)
>>
>>> I have some questions before doing a complete the review:
>>>
>>> = C++11 compatibility =
>>>
>>> * Does the library use c++11 features when available? I was thinking e.g.
>>> on
>>> the emulated virtual specifiers. BTW, I think the "new" virtual specifier
>>> was removed from the standard, but maybe I'm wrong.
>>> * I think the library don't allow to declare C++11 specific
>>> classes/function. E.g
>>> * variadic templates
>>> * noexcept functions
>>> * constexpr functions
>>> * class/function attributes
>>
>> The library is written for C++03 for now, while it emulates some C++11
>> features for C++03, the library doesn't support all C++11 features and
>> doesn't take advantage (go native) of them when available instead of
>> the emulated features. I am planning to extend the library to support
>> C++11 (the declaration syntax should be extendible without any
>> problem). I've added a ticket
>> https://sourceforge.net/apps/trac/contractpp/ticket/61
>
> I guess it will be better to have a ticket for each planned feature, so that
> they can be delivered one by one. For people that are using C++11, this
> could be a show-stopper for the library adoption, and IMO there are more and
> more that are moving to C++11.

Once I start supporting C++11 (which I could do before an eventual
Boost release), it should be easy enough to support *all* C++11 extra
declaration features at once. In most cases the lib has to simply
parse the pp syntax and generate the C++11 native code under-nit.

>>> BTW, I have not see any example using exception specifications using
>>> 'throws'. Does the library support them?
>>
>> Yes, for example:
>>
>> http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/contract__/advanced_topics.html#contract__.advanced_topics.exception_specifications_and_function_try_blocks
>>
>> http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/contract__/examples.html#contract__.examples.__cline90___stack__function_try_blocks_and_exception_specifications
>>
>> http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/contract__/grammar.html#contract__.grammar.exception_specifications
>
> Thanks, I have not yet read this part.
>
>>> Could you confirm? and if not, could you tell us if you have a plan to
>>> support them?
>>>
>>> = Postconditions result =
>>>
>>> "Postconditions can access the function return value by declaring a
>>> variable
>>> of type |auto| and assigning it to the |return| keyword (the variable
>>> name
>>> is arbitrary but |result| is often used)."
>>>
>>> What prevent the library to the use of return instead of an auto variable
>>>
>>> postcondition( // Postconditions.
>>> auto old_value = CONTRACT_OLDOF value, // Old
>>> value(s).
>>> value == old_value + 1, //
>>> Assertion(s)...
>>> return == old_value
>>> )
>>
>> This won't work if return is not the 1st token:
>>
>> old_value == return
>> 3 + return
>> myfync(return)
>> etc
>>
>> because there's no way the preprocessor can skip the leading tokens
>> given that they are unknown :( and they could contain symbols. I will
>> clarify this point in the rationale.
>
> OK. I understand.
>
>>
>>> instead of
>>>
>>> postcondition( // Postconditions.
>>> auto result = return, // Result value.
>>> auto old_value = CONTRACT_OLDOF value, // Old
>>> value(s).
>>> value == old_value + 1, //
>>> Assertion(s)...
>>> result == old_value
>>> )
>>>
>>> =Constant assertions =
>>>
>>> I would expect that the old are always const so the following
>>>
>>> postcondition(
>>> auto old_even = CONTRACT_OLDOF even,
>>> auto old_odd = CONTRACT_OLDOF odd,
>>> // `[old_]even` and `[old_]odd` all `const&` within
>>> assertions.
>>> const( even, old_even ) even == old_even + 2,
>>> const( odd, old_odd ) odd == old_odd + 2
>>> )
>>
>> old_... are const but you need to specify them in const( ... ) so they
>> can be accessed by the constant-assertion boolean condition:
>>
>> const( var1, var2, ... ) boolean-condition-using-var1-var2-...
>
> Why?

Because constant-assertions are implemented using local functions
which have such a limitation. Essentially, constant-assertions are
local function's constant blocks:
http://www.boost.org/doc/libs/1_51_0/libs/local_function/doc/html/boost_localfunction/examples.html#boost_localfunction.examples.constant_blocks
I'll document this rationale.

>> only global/static variables and var1, var2, etc can be used by
>> boolean-condition-using-var1-var2-... The docs are not clear abut this
>> point, I'll clarify it.
>>
>>> should be rewritten without loss of semantics as
>>>
>>> postcondition(
>>> auto old_even = CONTRACT_OLDOF even,
>>> auto old_odd = CONTRACT_OLDOF odd,
>>> // `[old_]even` and `[old_]odd` all `const&` within
>>> assertions.
>>> const( even ) even == old_even + 2,
>>> const( odd ) odd == old_odd + 2
>>> )
>>>
>>>
>>>
>>> = Oldof =
>>>
>>> As the old of value must be declared using a variable, using a specif
>>> oldof
>>> keyword that will replace
>>>
>>> auto old_size = CONTRACT_OLDOF size(),
>>> by
>>>
>>> oldofold_size = size(),
>>
>> This wont' work because the pp can't separate the trailing size()
>> expression for the rest because it can't deal with unknown tokens and
>> symbols like "size()" or "old_size". The expression:
>>
>> auto old_size = CONTRACT_OLDOF size()
>>
>> is parsed into type "auto", assignment "old_size =" (note that the pp
>> can't separate the = because it's a symbol and that required lots of
>> tricks to be handled correctly...), and the expression "size()". I
>> need all these separate traits to handle old-values while:
>>
>> oldofold_size = size()
>>
>> and even:
>>
>> oldof old_size = size()
>>
>> can't separate "old_size = size()" into "old_size" and "size()". The
>> macro CONTRACT_OLDOF expands into )( so at some point in the
>> CONTRACT_FUNCTION expansion this:
>>
>> CONTRACT_FUNCTION( ... auto old_size = CONTRACT_OLDOF size() ... )
>>
>> expands to (auto is know or wrapped within parenthesis the user):
>>
>> (auto) (old_size =) (size())
>>
>> which is ultimately a sequence and it can be handled by the pp.
>
> OK, I understand why you did this way now.
>
>>
>>> could simplify the syntax. What do you think?
>>>
>>> Some minor points:
>>>
>>> * Why do you use( void ) instead of () in the functions without
>>> parameters? e.g.
>>>
>>> public: bool empty ( void ) const { return vector_.empty();
>>> }
>>
>> Because MSVC pp gets confused with () even on C++11. On G++ you can
>> use () but the code might not always compile with MSVC :(
>>
>>
>> http://contractpp.svn.sourceforge.net/viewvc/contractpp/releases/contractpp_0_4_1/doc/html/contract__/tutorial.html#ftn.contract__.tutorial.free_functions.f3
>
> Note that the preceding example was just a function declaration with no
> macros, so I guess MSVC will be able to take care of
>
> bool empty ( ) const;
>
> isn't it?

Oops, no macros... so sure you can use empty ( ) instead of empty (
void ) but I'm always using a C++ declaration syntax that looks more
closely to the library's declaration syntax so programmers get more
familiar with it (e.g., ( void ), public:, etc). I'll mention this
rationale in the docs.

Thanks,
--Lorenzo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk