Boost logo

Boost :

Subject: Re: [boost] Boost.Algorithm design question
From: lcaminiti (lorcaminiti_at_[hidden])
Date: 2011-10-07 10:26:21


Andrew Sutton-3 wrote:
>
>> bool operator== ( orange const& l, apple const& r )
>>    { return l.weight == r.weight; } // comparing apples with oranges?!
>
> The expression "like comparing apples and oranges" is not usually
> meant to inspire confidence in the act of comparison. Just because
> it's legal doesn't make it good.
>
> A definition of equality should support equational reasoning. If two
> values are equal, then you should be able to substitute one for the
> other and produce an equivalent program. I seriously doubt that
> substituting an apple in place of an orange would produce an
> equivalent program; it will probably result in type errors. Objects of
> different types cannot be equal (with some exceptions).
>

Yes, my example was hinting that even if we can syntactically define orange
== apple maybe we shouldn't because its semantics will be obscure.

Here's an example (that compiles) to illustrate both option 1 and option 2
of the interface:

#include <boost/local/function.hpp>
#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

struct orange {
    int weight;
    int c_vitamin;
};

struct apple {
    int weight;
};

bool operator== ( orange const& l, apple const& r ) {
    return l.weight == r.weight; // confusing semantic??
}

bool operator== ( orange const& l, orange const& r ) {
    return l.weight == r.weight && l.c_vitamin == r.c_vitamin;
}

template< typename Iter, typename Value >
    // requires InputIterator<Iter>,
    //
EqualityComparable&lt;iterator_traits&lt;Iter&gt;::value_type, Value>
Iter find_opt1( Iter first, Iter last, Value const& val ) {
    return std::find(first, last, val);
}

template< typename Iter >
    // requires InputIterator<Iter>
    //
EqualityComparable&lt;iterator_traits&lt;Iter&gt;::value_type>
Iter find_opt2( Iter first, Iter last,
        typename std::iterator_traits<Iter>::value_type const& val ) {
    return std::find(first, last, val);
}

int main ( ) {
    std::vector<orange> v(2);
    apple a;
    orange o;

    find_opt1(v.begin(), v.end(), a); // OK but does it make sense?

    find_opt2(v.begin(), v.end(), o); // OK and clear, we're comparing
orange with oranges
// find_opt2(v.begin(), v.end(), apple()); // correctly, compiler error

    // can still compare just weights with predicate version:
    bool BOOST_LOCAL_FUNCTION_PARAMS( orange const& l, const bind& a ) {
        return l.weight == a.weight;
    } BOOST_LOCAL_FUNCTION_NAME(same_weight)
    std::find_if(v.begin(), v.end(), same_weight); // clear, we're comparing
just weights

    return 0;
}

Again, I'm thinking that the semantics of option 2 are more natural (because
it is confusing to be able to compare apples with oranges) but IMO
Boost.Algorithm should clearly explain why it is deviating from STL if it
adopts option 2 instead of option 1.

P.S. Are the < > still messy?

Thanks,
--Lorenzo

--
View this message in context: http://boost.2283326.n4.nabble.com/Boost-Algorithm-design-question-tp3876424p3882387.html
Sent from the Boost - Dev mailing list archive at Nabble.com.

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