Boost logo

Boost :

Subject: Re: [boost] [GSoC] [Boost.Hana] Formal review request
From: Louis Dionne (ldionne.2_at_[hidden])
Date: 2014-08-01 17:52:22


pfultz2 <pfultz2 <at> yahoo.com> writes:

>
> [...]
>
> But as user if I was defining my own `sum` function, how would I do it? I
> can't change the typeclass, since it is in another library. Is there a way
> for me as an user to optimize my sum function based on which MCD was
> implemented? And if so, couldn't the library do the same?

Well, if you define the `sum` function, that's because you are defining an
instance of the corresponding type class (Foldable). Hence, you are already
choosing the MCD:
    
    namespace boost { namespace hana {
    template <>
    struct Foldable::instance<YourDatatype> : Foldable::the_mcd_you_want {
        // minimal complete definition here

        template <typename Xs>
        static constexpr auto sum_impl(Xs xs) {
            // your custom sum implementation
        }
    };
    }} // end namespace boost::hana

Am I missing your point?

> > If you go look at the Foldable type class in Haskell, you'll see that
> > there
> > are a bunch of related functions provided with the type class, yet they
> > are
> > not included in it. My opinion is that they might just as well be included
> > in the type class, as you could then redefine them for improved
> > performance.
> > I just searched online for a rationale or at least some insight about this
> > decision, but I did not find anything.
>
> I think the rational is similar to the rational for using non-member
> functions. One reason is consistency. People are going to add new
> algorithms, but they won't be added to the typeclass. Futhermore,
> if they want to allow overloading the algorithm for optimization,
> they will create new typeclasses. So now you have two different ways
> to accomplish the same thing.

The truth is that I think users should not feel the need to add methods to
existing type classes. If a method can be implemented in a type class _and_
has a general utility, then it should be added to the type class for everyone
to benefit. If, however, you need more "structure" than provided by existing
type classes to do something, then you create a new type class which carries
that additional "structure" and in which you can implement more operations.
That's how I see it.

> Another reason, is it will make the typeclass simpler and improve
> encapsulation. A typeclass is defined by the minimum necessary and
> not by another 50 algorithms.

I disagree. Type classes are _already_ defined by their minimal complete
definition(s). While this is not the case in the current documentation,
I'd like to actually document an equivalent implementation for each method
using only methods in a minimal complete definition. That would make it more
obvious that type classes are defined by their MCDs.

> > > - It's important to note that the `decltype_` function will only work
> > > for constexpr-friendly types.
> >
> > I don't get it? Can you please expand?
>
> I should clarify that I'm referring to the use of `decltype_` within the
> context of constexpr. It will work outside of that. So, for example, if I
> were
> to static_assert that two types were the same, as a simple example:
>
> template<class T>
> void foo(T x)
> {
> auto y = bar();
> static_assert(decltype_(x) == decltype_(y), "Not matching types");
> }
>
> This won't work for if types are not a literal type nor have a constexpr
> constructed. This will fail even if `decltype_` was to take the expression
> by reference. Ultimately, I believe the language should be changed to allow
> for this.

It should work; Hana was designed exactly to deal with that. Here's what
happens (that's going to be in the tutorial also):

1. decltype_(x) == decltype_(y) returns a bool_<true or false>
2. bool_<b> has a constexpr conversion to bool defined as:
    
    template <bool b>
    struct bool_type {
        constexpr operator bool() const { return b; }
    };

Since the conversion is always constexpr, it's used in the `static_assert`
and it works. Now, it does not __actually__ works because of what I think
is a bug in Clang. For it to work, you have to define a dummy object like
that:

    template <typename X, typename Y>
    void foo(X x, Y y) {
        auto dummy_result = decltype_(x) == decltype_(y);
        static_assert(dummy_result, "");
    }

And that will compile. Am I exploiting some hole in Clang or is this correct
w.r.t. C++14? I'm unfortunately not really a standards guy, so if someone can
help here that'd be helpful.

Regards,
Louis


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