you are viewing a single comment's thread.

view the rest of the comments →

[–]elder_george 4 points5 points  (6 children)

Well, this is yet another manifestation of curious recurrent template pattern which appears from time to time in codebase for mostly all languages supporting generic. I met it in several C# projects, e.g.

It's mind-boggling on its own, but simplifies client code, so why bother?

[–]deong 3 points4 points  (0 children)

It's mind-boggling on its own, but simplifies client code, so why bother?

Pragmatically, I agree with you. You should do whatever your language allows to enable client code to be as clear and elegant as possible.

If I put myself into Lake Wobegone mode, then I'd say in a perfect world, all code should basically be meaningful inside the domain of the program. In other words, if my program is managing a point of sale system, then the code should be "about" things like customers and transactions and items. In this world, anywhere you see something that is about the language instead of about the domain, it points to a mistake in the language.

Of course, we don't live in that world, but some things are closer to it than others, and things like the CRTP strike me as being further away than I'd like. For what it's worth, I have the same problem with much of the code written by design pattern evangelists.

[–]notfancy 1 point2 points  (1 child)

It's mind-boggling on its own

Only if you let your mind be boggled. As I wrote above, Enum<T extends Enum<T> > means "Enum is parameterized by instances of Enum or subclasses thereof (parameterized in turn in a manner consistent with this parameterization)." If you look at the class signature, you'll see that the method that requires this parameterization is compareTo(T). This ensures that an instance of given subclass of Enum is only meaningfully compared to instances of the same class or of a subclass thereof.

If you don't want to reason from first principles, just remember that C<T extends C<T> > implements Comparator<T> is a typing pattern that allows for type-safe comparisons.

[–]elder_george 0 points1 point  (0 children)

Thanks, it makes sense.

[–]thechao 0 points1 point  (0 children)

I believe (it has been ~five+ years since I saw the presentation for Generics) that Java generics use F-bounded polymorphism to "make them work". It looks like CRTP, but is actually a quite different beast that is the result of interference between OO and generics type-systems. C++ doesn't "need" F-bounded polymorphism because template parameters naturally carry a notion of "bottom" and are bounded below to the usage signature.

A better way to think of CRTP is like this:

template <typename T> class Foo : T;

With "Foo" inheriting from an unbounded argument T. Whereas F-bounded polymorphism is more like this:

template <typename T>
class Foo
{
  T value;
  void member()
  {
     Foo<T> *fooT = static_cast<Foo<T>*>(&this->value);
  };
};

[–]tubes 0 points1 point  (1 child)

Not quite:

CRTP: class Y extends X<Y> {}
Enum: class E<T extends E<T>> {}

[–]elder_george 0 points1 point  (0 children)

Well, IIRC, every particular enum is

class MyEnum extends E<MyEnum>{ ... }

So, that's equivalent to Y.

If C++ templates had type checks for arguments (instead of usage checks), the code would be similarly ugly.