Boost logo

Boost :

Subject: [boost] Hana Typeclass
From: Robert Ramey (ramey_at_[hidden])
Date: 2014-08-03 14:32:25


I can't review the whole library. So I'm confining my observations to just a
couple of aspects. My method is
to review some section of the documentation. it looks like a critique of the
documentation, but it's really
observations on the underlying design of the library.

In this post I'm addressing Typeclass.

Typeclass

"Conceptually, type classes are an artifice allowing humans to manipulate
objects of heterogeneous types with well-defined semantics.

OK

They serve a purpose very similar to C++ concepts (which are not in yet) and
to Haskell type classes, except they do not have language support"

OK - But I would argue that C++ concepts do have library support. It may
not be perfect, but it's good enough for government work.

template <class T>
struct Printable {
private:
    T t;
    std::ostream os;
public:
    BOOST_CONCEPT_USAGE(Printable)
    {
        os << t;
    }
};

"Type classes in Boost.Hana are a library-level implementation of such type
constraints allowing us to organize our generic programming."

When I read this it seems to be identical to the definition of what Boost
Concept Checking is.

"Getting concrete"

Here is where we start to have problems. Rather than the simple BCC example
above, we've got something a lot more complex and hard to understand. the
example

struct Printable {
    BOOST_HANA_TYPECLASS(Printable);
    // This is valid, but it's probably not a good idea unless those are
    // strongly related to the type class.
    int foo;
    void bar() const { };
    struct baz { };
};

Describes what not to do - but doesn't describe what one is supposed to do.

"As you will see later with minimal complete definitions, it is often useful
to put other related members in a type class; don't hesitate to do it when
it makes sense."

Upon reading this - we don't know enough to know that "related members"
means and what it means to "make sense".

"When I introduced type classes, I said they allowed us to bundle together
related operations called methods. This is because type classes can be seen
as defining some kind of public interface consisting of the operations that
are valid with any object satisfying some constraints"

which is the C++ concept - or my own "type constraint"

"I also said that they made it possible to explicitly state that a type
satisfies those constraints, and how it does so"

I would phrase this differently:

explicitly state what operations must be valid when applied to a given type
in order to deem it as fulfilling the "type constraints"

"From now on, I will refer to the set of all types satisfying the
constraints of a type class T as the instances of T"

A big problem as far as I'm concerned. In C++ we use the phrase "instance
of type T" for an entirely different thing.

I would use the phrase: a "Printable" type - in the case of the example
above. When referring to a set of type constraints I would pick something
like "modeling the type constraints T or modeling the Printable type". This
is familiar language to us.

"To associate methods to a type class, we create a layer of indirection
through the instance member of the type class. For example, let's say we
want to have a method named print in the Printable type class:
…"

The whole rest of this section goes into how to create a set of types
modeling "Printable". OK - But why is this necessary at all? If one tries
something like:

template<class T>
void f(T & x) {
        BOOST_CONCEPT_ASSERT((Printable<T>));
        std::cout << x;
}

class x {
};

f(x); // compile time error here

the program will trap at compile time with an error inside of Printable
indicating that f doesn't model Printable because the operation ostream << x
isn't supported by x; That's what I need.

With type class it looks like that is expected that there be a default
implementation for f if x isn't printable. It's not at all clear what this
default definition is supposed to do. Print default error message at
runtime? or
what? The documentation notes that the usage of a default would be rare.
But if it were to be used - it conflicts with the original purpose if type
constraints (or concepts or type classes, etc).

It's still not clear to me what happens if I use your type class system and
invoke f(x). Do I get a compile time error? - what kind? where does it
point to? How does it help the user find his error?

To me the "type class" of the Hana library is a muddled re-implemenation of
the boost concept check library. Its much more complicated and subtle and
not as well documented and doesn't add anything to BCC.

Robert Ramey

--
View this message in context: http://boost.2283326.n4.nabble.com/Hana-Typeclass-tp4665978.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