[parameter] type predicates vs. concepts

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[parameter] type predicates vs. concepts

lcaminiti
Hello all,

What's the difference between using a Boost.Parameter type predicate
and using a concept?

I think parameter type predicates are unary metafunctions used to
resolve the function call, concepts are asserted on the type after the
call has been resolved... Is there more? Can I always do with type
predicates what I can do with concepts? Is there ever a reason to
use/need both?

For example here has_equal_to is the type predicate while
DefautlConstructible is the concept. Could/should I have used
has_[...]_default_constructor in and_ the type predicate instead of
the DefaultConstructible concept?

#include <boost/parameter.hpp>
#include <boost/concept/requires.hpp>
#include <boost/concept_check.hpp>
#include <boost/type_traits/has_equal_to.hpp>
#include <iostream>

template< typename X >
BOOST_CONCEPT_REQUIRES( ((boost::DefaultConstructible<X>)), (bool) )
is_default_impl ( X const& x )
{
    return x == X();
}

BOOST_PARAMETER_NAME(x)

BOOST_PARAMETER_FUNCTION(
    (bool),
    is_default,
    tag,
    (required (x, *(boost::has_equal_to<tag::x::_>)) )
) {
    return is_default_impl(x);
}

struct no_equal {};

struct no_default { no_default(int) {} };
bool operator== ( no_default const&, no_default const& ) { return true; }

int main ( void )
{
    std::cout << is_default(123) << std::endl; // ok
    // parameter error: cannot resolve is_default() call
//    std::cout << is_default(no_equal()) << std::endl;
    // concept error: no default constructor
//    std::cout << is_default(no_default(1)) << std::endl;
    return 0;
}

Thanks a lot.
--Lorenzo

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

Jeffrey Lee Hellrung, Jr.-2
On Sun, Dec 4, 2011 at 10:23 AM, Lorenzo Caminiti <[hidden email]>wrote:

> Hello all,
>
> What's the difference between using a Boost.Parameter type predicate
> and using a concept?
>
> I think parameter type predicates are unary metafunctions used to
> resolve the function call, concepts are asserted on the type after the
> call has been resolved... Is there more? Can I always do with type
> predicates what I can do with concepts? Is there ever a reason to
> use/need both?
>
[...]

I'd imagine some concepts checking classes cannot be translated into a
strictly equivalent metafunction, especially for C++03.

Also, the error message typically generated for a failed Boost.Concept
assertion might be more desirable than that for a failing to find a
compatible overload due to the use of SFINAE and metafunctions.

- Jeff

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

Dave Abrahams
In reply to this post by lcaminiti

on Sun Dec 04 2011, Lorenzo Caminiti <lorcaminiti-AT-gmail.com> wrote:

> Hello all,
>
> What's the difference between using a Boost.Parameter type predicate
> and using a concept?
>
> I think parameter type predicates are unary metafunctions used to
> resolve the function call, concepts are asserted on the type after the
> call has been resolved... Is there more?

Overload ordering on concepts, but I see you're not talking about real
concepts, just BCCL concepts.

> Can I always do with type predicates what I can do with concepts?

No, type predicates are required not to cause a compilation error, so
there are limits to what they can detect in C++03 (e.g. copyability).
Concept checks are specifically used to cause compilation errors.

> Is there ever a reason to use/need both?
>
> For example here has_equal_to is the type predicate while
> DefautlConstructible is the concept. Could/should I have used
> has_[...]_default_constructor in and_ the type predicate instead of
> the DefaultConstructible concept?

I think unless the compiler has implemented a special intrinsic, in
C++03 has_[...]_default_constructor is at best an imperfect emulation.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

Dave Abrahams
In reply to this post by Jeffrey Lee Hellrung, Jr.-2

on Sun Dec 04 2011, "Jeffrey Lee Hellrung, Jr." <jeffrey.hellrung-AT-gmail.com> wrote:

> Also, the error message typically generated for a failed Boost.Concept
> assertion might be more desirable than that for a failing to find a
> compatible overload due to the use of SFINAE and metafunctions.

Good point.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

lcaminiti
In reply to this post by Dave Abrahams
On Thu, Dec 15, 2011 at 7:18 AM, Dave Abrahams <[hidden email]> wrote:

>
> on Sun Dec 04 2011, Lorenzo Caminiti <lorcaminiti-AT-gmail.com> wrote:
>
>> Hello all,
>>
>> What's the difference between using a Boost.Parameter type predicate
>> and using a concept?
>>
>> I think parameter type predicates are unary metafunctions used to
>> resolve the function call, concepts are asserted on the type after the
>> call has been resolved... Is there more?
>
> Overload ordering on concepts, but I see you're not talking about real
> concepts, just BCCL concepts.

Yes, I'm referring to Boost.Concept-- even with C++11 that's all we'll
have, right?

>> Can I always do with type predicates what I can do with concepts?
>
> No, type predicates are required not to cause a compilation error, so
> there are limits to what they can detect in C++03 (e.g. copyability).
> Concept checks are specifically used to cause compilation errors.
>
>> Is there ever a reason to use/need both?
>>
>> For example here has_equal_to is the type predicate while
>> DefautlConstructible is the concept. Could/should I have used
>> has_[...]_default_constructor in and_ the type predicate instead of
>> the DefaultConstructible concept?
>
> I think unless the compiler has implemented a special intrinsic, in
> C++03 has_[...]_default_constructor is at best an imperfect emulation.

1) As you pointed out, there are conditions we can program with
concepts but not with type predicates (imperfect type traits, etc). Is
the opposite true: Can I always program a concept if I can program a
type predicate? I'd think so...
2) As pointed out by Jeff, another difference is in the error
reporting-- concept failures might be more informative than a SFINAE
saying "can't resolve an overloaded function call" (because it doesn't
say which type failed which requirement).
Any other difference? Any "theoretical" difference?

I'm asking because Boost.Contract will support both type predicates
and concepts so I need to tell the users why they can use both, when
to use concepts, and when to use type predicates. Actually,
Boost.Parameter also supports both because it can be used together
with Boost.Concept so IMO it'd be nice to add the same explanation to
Boost.Parameter as well.

Thanks.
--Lorenzo

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

Jeffrey Lee Hellrung, Jr.-2
On Thu, Dec 15, 2011 at 8:26 AM, Lorenzo Caminiti <[hidden email]>wrote:
[...]

> I'm asking because Boost.Contract will support both type predicates
> and concepts so I need to tell the users why they can use both, when
> to use concepts, and when to use type predicates. Actually,
> Boost.Parameter also supports both because it can be used together
> with Boost.Concept so IMO it'd be nice to add the same explanation to
> Boost.Parameter as well.
>

I don't think Boost.Contract nor Boost.Parameter is special in this regard.
The guideline I follow is: use type predicates only to differentiate
between overloads via SFINAE; otherwise, use concept assertions, as they
typically provide more informative error messages and don't complicate the
function signature.

- Jeff

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

Dave Abrahams

on Fri Dec 16 2011, "Jeffrey Lee Hellrung, Jr." <jeffrey.hellrung-AT-gmail.com> wrote:

> On Thu, Dec 15, 2011 at 8:26 AM, Lorenzo Caminiti <[hidden email]>wrote:
> [...]
>
>> I'm asking because Boost.Contract will support both type predicates
>> and concepts so I need to tell the users why they can use both, when
>> to use concepts, and when to use type predicates. Actually,
>> Boost.Parameter also supports both because it can be used together
>> with Boost.Concept so IMO it'd be nice to add the same explanation to
>> Boost.Parameter as well.
>>
>
> I don't think Boost.Contract nor Boost.Parameter is special in this regard.
> The guideline I follow is: use type predicates only to differentiate
> between overloads via SFINAE; otherwise, use concept assertions, as they
> typically provide more informative error messages and don't complicate the
> function signature.

I mostly agree, but there are a few exceptions to that rule.  One is
when you're writing conversion operators, constructors, or other
operations with broadly-understood semantics: if you don't use SFINAE to
take them out of contention when they don't apply, then other people
using traits (usually relying on SFINAE tricks themselves) will get the
wrong answer for, e.g., is_convertible<T,U>, has_addition<T>, etc.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com


_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [parameter] type predicates vs. concepts

lcaminiti
Dave Abrahams wrote
on Fri Dec 16 2011, "Jeffrey Lee Hellrung, Jr." <jeffrey.hellrung-AT-gmail.com> wrote:

> On Thu, Dec 15, 2011 at 8:26 AM, Lorenzo Caminiti <[hidden email]>wrote:
> [...]
>
>> I'm asking because Boost.Contract will support both type predicates
>> and concepts so I need to tell the users why they can use both, when
>> to use concepts, and when to use type predicates. Actually,
>> Boost.Parameter also supports both because it can be used together
>> with Boost.Concept so IMO it'd be nice to add the same explanation to
>> Boost.Parameter as well.
>>
>
> I don't think Boost.Contract nor Boost.Parameter is special in this regard.
> The guideline I follow is: use type predicates only to differentiate
> between overloads via SFINAE; otherwise, use concept assertions, as they
> typically provide more informative error messages and don't complicate the
> function signature.

I mostly agree, but there are a few exceptions to that rule.  One is
when you're writing conversion operators, constructors, or other
operations with broadly-understood semantics: if you don't use SFINAE to
take them out of contention when they don't apply, then other people
using traits (usually relying on SFINAE tricks themselves) will get the
wrong answer for, e.g., is_convertible<T,U>, has_addition<T>, etc.
I think a (bad) example of that is the implementation of operator== for std::vector<T> which is not taken out of overload resolution using SFINAE when T does not have an operator==. Then has_equal_to< std::vector<T> > is true even when has_equal_to<T> is false, making necessary to explicitly specialize has_equal_to for vectors (and other containers) to work around this :(

Another example of when you want SFINAE to fail the overload instead of a concept error is to distinguis deduced parameters for which you will always use type predicates (as far as I can tell).

(I will add the result of this discussion to Boost.Contract docs.)

--Lorenzo