2013/7/1 Durchholz, Joachim <[email protected]>

> This:
> >
> http://blog.jooq.org/2013/06/28/the-dangers-of-correlating-subtype-polymorphism-with-generic-polymorphism
>
> I'm seeing the point you're making, but I don't think that making
> everything final is a good solution. It's certainly a massive restriction
> on what one can do with the classes.
> It's a bit like making everything private so that subclasses cannot do
> wrong, instead of accepting that subclasses aren't very much encapsulated
> against their superclasses and have an obligation to be particularly
> cautious.
>

I'm not advocating making everything final. I'm saying that making any
recursive / self-bound *terminator* final is the only way to *guarantee*
that the contracts introduced by the recursive self-bound in the first
place won't be broken. In other words, I'm saying that it is extremely
dangerous to "terminate" a recursive self-bound in an interface or public
API class in terms of API consistency and evolution, because any subtype of
the "terminator" type is likely to break "uptype" contracts.

That is quite an academic claim in every-day programming life, of course.
It is not academic in an API like jOOQ.


> In particular since I make subclasses of classes that you'd advocating be
> made final all the time.
>
> The real problem, BTW, is the parameter types.
> You can't vary them covariantly without breaking type safety (a caller
> that expects a supertype may call the function with a too general type).
>
> IOW if we have
>
> class Parent<E> {
>   void f(E e);
> }
> class Child extends Parent<Number> {
>   void f(Number e) {
>     // do something that assumes e is a Number
>   }
> }
>
> and we can do
>
>   breakage(Parent<?> p, Object o) {
>     p.f(o);
>   }
>
> then that's already breaking, even without having a subclass of Child.
>
> The same can already happen if Child just narrows the type, without
> actually substituting in a type parameter:
>
> class Child <N extends Number> extends Parent<N> {
>   void f(N e) {
>     // do something that assumes e is a Number
>   }
> }
>
> In a sense, I suspect the blog post is itself mixing subtype and generic
> polymorphism up :-)
>

On purpose. The whole post is about the common mistake of blending the two
polymorphism axes without sufficient care. Adding a recursive self-bound on
an API super-type is asking for trouble across all subtypes, be they part
of the API or part of the user code. Or more concretely - to get back in
jOOQ context, and to your original example which made me write that post:

*Adding <Q extends QueryPart<Q>> would be a big mistake.*

That's all that post is saying :-)

Maybe we're just seeing things from different perspectives.


Probably. Mine is that of an API designer who has committed to the rules of
semantic versioning. I'm very "afraid" of such bold moves in my API's type
system.


> Mine is that Java's subtyping guarantees are only "best effort", I'm not
> surprised if Java recognizes something as a subtype that isn't, and am
> prepared to live with ClassCastExceptions. Your perspective seems to be
> that if Java recognizes something as a subtype that isn't, that must be
> prevented because it's wrong if there's a loophole for ClassCastExceptions.
> My answer to that would be: You already have ClassCastExceptions, trying to
> prevent these is just going to make your life even more miserable. YMMV :-)
>
> I won't claim that my perspective is the more valid one.
> I do claim, however, that the blog post is stating things as if these were
> conceptual, basic limitations and that generically instantiated types must
> always be made final to achieve type safety; this is only marginally
> correct in Java, and entirely incorrect in languages with differently
> constructed type systems (most FPLs fall into the latter category atually).


Then, you might not have gotten the point of my blog post - or it wasn't
written concisely enough. The whole post was about:

- Correlating subtype and parametric polymorphism in a given type hierarchy
in general
- Correlating the two on the same type through recursion in particular

Your "Child<N extends Number> extends Parent<N>" example does not correlate
Child/Parent (subtype) with <N> (parametric) type axes. The two axes are
independent from one another. So, my post does not apply to your example
and you won't run into the trouble I was trying to point out.

-- 
You received this message because you are subscribed to the Google Groups "jOOQ 
User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to