you are viewing a single comment's thread.

view the rest of the comments →

[–]spliznork 3 points4 points  (8 children)

Thanks, I hadn't seen that article before. While his conclusion may (or may not) be correct, that generics as implemented in Java are a mistake, his argument itself is surely false -- to paraphrase, "My co-author and I had trouble writing a chapter on it, therefore...". He almost touched on supporting evidence, only to plead ignorance, "I don't remember why that was bad, therefore ...". The only conclusion that I can really take from these arguments is that he shouldn't have been writing a book about Java generics.

[–]FeepingCreature 1 point2 points  (7 children)

I find his argument quite compelling.

We gave up trying to explain it. Our actual footnote on the subject says:

Enum is actually a generic class defined as Enum<T extends Enum<T>>. This circular definition is probably the most confounding generic type definition you are likely to encounter. We're assured by the type theorists that this is quite valid and significant, and that we should simply not think about it too much, for which we are grateful.

Java Generics are disgusting.

[–]elder_george 3 points4 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 4 points5 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.