Boost logo

Boost :

Subject: Re: [boost] [Review] GGL review starts today, November 5th
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2009-11-08 09:53:01


Hi,
----- Original Message -----
From: "Barend Gehrels" <barend_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Sunday, November 08, 2009 2:34 PM
Subject: Re: [boost] [Review] GGL review starts today, November 5th

>
> Hi Vicente,
>
>
> Thanks for diving into our library.

You are welcome.
 
>> Note that I have just read the introduction of the documentation and I find the it quite clear.
>>
>
> Good to hear.
>
>> Some words about SNIFAE and partial specialization:
>>
> I've no problem to rephrase the documentation-section about SFINAE or
> even to omit it. The section documents our choice for tag dispatching,
> but it might be not necessary to do it in this detail. I've also no
> problems with SFINAE in general, it is just a preference for usage in
> more complex libraries like GGL.
>
> We've used SFINAE in the past, for about half a year, in GGL. However,
> we did have much problems with it, getting it all right and compiling it
> on all compilers. We especially did have troubles with the boost concept
> checking in combination with sfinae (maybe I should add that). Dave
> Abrahams wrote about this (I quote here from a mail in january 2009):
>
>>
>> > Barend: (...) This works perfectly and distinguishes all geometry types at compile
>> > time, as long as the library or the developer provides the meta function
>> > geometry_type<T>::type which is currently implemented as an enumeration
>> > of TYPE_POINT, etc.
>>
>>
>> Dave: Seems like you might be better off using tag dispatching...
> We went over to tag dispatching and all those problems disappeared.
>
> Maybe I should add (if the section is not going to be omitted) that the
> combination of SFINAE and the BCCL using boost-concept-requires was
> quite difficult. I Just rechecked some things and I think this still is
> the case. I checked using a small source with things as "apple", "pear",
> "banana", so you'll see them in my answers.

If there is a clear justification that SFINAE and BCCL do not matches, his should be added in the rationale. But don't we use SFINAE to support concepts? I don't see the need to combine them. Remember that there was a Concept Traits library that was intendedd to replace the BCCL. The library was abandoned because C++0x should include concepts and because some concepts couldn't be managed by traits. Maybe this library should be relaunched as Concepts are not part of C++0x now.
  
>> [snipped] Even if you neded SFINAE, and if I'm not wrong enable_if can also be applied to structs. From enable_if docummentation "
>> Enabling template class specializations
>> Class template specializations can be enabled or disabled with enable_if. One extra template parameter needs to be added for the enabler expressions. This parameter has the default value void. For example:
>> template <class T, class Enable = void>
>> class A { ... };
>>
>> template <class T>
>> class A<T, typename enable_if<is_integral<T> >::type> { ... };
>>
>> template <class T>
>> class A<T, typename enable_if<is_float<T> >::type> { ... };"
>>
>
> That is indeed possible, just tried it with enable_if.
>
> But, technically speaking, I don't think this is SFINAE. I think it is
> partial specialization, and specialization is done here on
> enable_if<...>::type, finding matching candidates and if no one is
> found, using the unspecialized class. We don't have the real
> "Substitution Failure" here, where one or more overloads are discarded
> from the candidate set based on failing substitution.
>
> So these classes with enable_if work about the same way as tag
> dispatching does, though no tag is necessary. But also here I prefer tag
> dispatching because (my personal opinion) I find it resulting in more
> readable code.
>
>
>>> *gives often compiler troubles and headaches: if a user makes an error somewhere, the compiler will not select any of the methods, and/or it will give completely incomprehensible error listings, just because of this SFINAE"
>>>
>>
>> I thought that this was and advantage not a liability. The message is short: method not found.
>> What errors do you get when a user makes an error somewhere with tag dispatching? Are they clearer?
>>
> The messages you get depend on the type or error, in both cases.
>
> When I try to use a function based on sfinae, when there is no match,
> is: the message I get
> - from MSVC is: Failed to specialize function template..., for all
> overloads.
> - from gcc is: no matching function for call to.... (one)
>
> On tag dispatching you'll get:
> MSVC: 'type' : is not a member of 'tag<T>' with [T=banana]
> gcc, similar
>
> or (if the banana-tag is implemented)
>
> MSVC: 'apply' : is not a member of 'dispatch<T>' with [T=tag<banana>::type]
> gcc: 'apply' is not a member of 'dispatch<banana_tag>'

This message could be clear to you, but what the user is intendeed to do to correct the error?
 
> sfinae is based on overloads, and the problem I encountered with it (and
> with its messages) that in case of errors I often don't understand where
> the error originates from. I remember having to number several times all
> overloads (of e.g. "eat") to e.g. eat1, eat2, eat3, etc, to see what is
> actually going wrong and why the overload was not called in that
> specific case.
>
> With tag dispatching you can also get pages of messages, but it is more
> clear where they come from, e.g. a missing specialization, a wrong input
> type.
>
>
>>
>>> * does not support partial specializations because it is a function. The tag-dispatching function is of course also not supporting that, but it forwards its call to the dispatch struct where partial specializations (and member template functions) are possible. The SFINAE could do that as well but then: why not just add one tag more and have tag dispatching instead?"
>>>
>>
>> Could you clarify which is the tag you add?
>>
>
> If I understand your question: we're adding a geometry-tag. So for a
> point it specializes to point_tag, etc.
>
> What is meant by this section is that for some cases, code is similar.
> For example the "num_points" algorithm, the number of points of a
> linestring is the same as the number of points of a linear ring. The
> dispatch function can specialize partially on this similarity. I now
> realize, by just doing some re-checking that for SFINAE you can do the
> same, using SFINAE on a specific property to define an overload which
> applies to more than one geometry.
>
> So this sentence probably can go, it is possible in both cases.

I agree.
 
>>
>>> * is a trick to deceive the compiler. "As a language behavior it was designed to avoid programs becoming ill-formed" (http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error), while tag dispatching is based on specialization, a core feature of C++
>>> * looks more ugly
>>>
>>
>> You know that this is a matter of taste, and the way you do force the user to share your taste.
>>
> I can rephrase this. What I mean is that a function
>
> template <typename T>
> void eat(T const& fruit)
> {
> // tag dispatch on apple-tag
> }
>
> looks better than:
>
> template <typename T>
> void eat(T const& fruit
> #ifdef DOXYGEN_SHOULD_SKIP_THIS
> , typename boost::enable_if<typename is_apple<T>::type>::type* = NULL
> #endif
> )
> {
> // (call) apple implementation
> }

Why the user can not define eat on the namespace the apple class is defined

namespace apple_ns {
    void eat(apple const& fruit)
    {
        // do apple implementation
    }
}
 
Do you see a problem with this approach?

> Maybe I should state "makes the main free function declarations shorter"
> to be more objective.

[snipped]

>> [snipped] Do you think that this could be also applied to the GGL library at least for the concepts?
>>
> Interesting, I'll react on the convert_to in another e-mail later.

Happy to hear,
Vicente


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