Thomas Hawtin said:
A duplicate of the concerns about dynamic polymorphism.
Absolutely not. I'd try to respond to your statement, except that you
didn't really do anything except make a claim that is non-sensical at
first glance, and then fail to explain it. I can't imagine what you
could possibly mean.
After Alan, it's all cosmetic.
No, it's not. Surely you don't really believe that the only difference
between a Turing machine and a modern programming language is
aesthetics? Namely, modern programming languages excel at using (and,
in some cases, building) abstractions that make sense within the context
of the problem being solved. Sure, there's a blurry line between that
and programming style; but we're not dealing with the blurry part of
that line here. We are looking at a very clear-cut case; complicate the
abstraction, for the sake of your pet programming style. That
programming style is in NO WAY related to expression of any important
aspects of the problem space or solution space.
That's the scary part, here. It's been understood for some time that
generics would encourage people to abandon abstraction in some of the
blurry areas, and it's been accepted as a consequence (even perhaps a
positive one) of introducing an easier way to write code without that
abstraction. That, in itself, presents tough trade-offs. But here,
there is hardly a trade at all; it's basically a matter of exposing
complexity just for complexity's sake.
I'm not changing the fundamental nature of anything.
Sure you are. You are adding a type parameter. That's not an
insignificant change. You're creating a whole range of possible types,
when really you just meant to create one.
I'm just saying
that a type may or may not have a subtype. With a StringBuilder you take
it on trust that the append method really do return the same object.
Here you trust that THIS is for this (where there is less room for
surprise).
I don't understand your point. Do you have trouble trusting the API
documentation? What does trusting a published interface have to do with
whether that published interface is unreasonably complex or not? I also
trust the published interface for a good number of other complex APIs,
but I don't think it's a good idea to make an API more complex than it
needs to be.
Encapsulation - This is a builder. It puts two finger up to
encapsulation. It is no more or less encapsulated than a method with 255
params.
Abstraction - I'm not seeing the difference with this and any other builder.
I'm entirely confused as to what you're trying to say, here.
Separation of interface from implementation - The technique works fine
even with Java interfaces.
I didn't mean the Java interface keyword. I meant separation of
interface from implementation in the deeper sense of the word... the
sense in which every class has BOTH an interface and an implementation.
It would be if a clone-like method was implemented...
No, even then the functionality of the class is not parameterized.
What you seem to want is to overcome a limitation of Java's pre-1.5 type
system, namely the lack of covariant return types. The desire to use
covariant return types is not an indication that something is different
in the nature of the type. It's just an indication that Java's pre-1.5
type system was unnecessarily limited.
Fortunately, Java 1.5 introduced covariant return types in addition to
generics, solving your difficulty. That's beside the point, though.
The point is this: Even if you didn't have covariant return types
available, the solution would NOT be to change the exposed public
interface of a class. It would be to bite the bullet and perform the
cast in IMPLEMENTATION code that uses the API. Or to choose an equally
valid implementation technique that doesn't require the cast. In any
case, your desire to pull the programming equivalent of a play on words
to save some typing doesn't justify changing a class's public interface,
much less its very nature as a single type.
It's all about data, not processes. Really it's the same kind of thing
in the same statement. It actually keeps the client code clean.
I think it's the meaning of "clean" here that is the root of the
problem. If the change expressed some significant aspect of what the
code is trying to do, then I'd have no objection. Instead, it's saving
you from typing a reference name. (And, in the unique case of a
superclass contructor invocation, it saves you from the need to declare
a private static method in which to do the work.)
There is a cost in that it might not be immediately apparent what THIS
is. But if it cleans up configuration, then I'm all for it (even if I am
alone).
The cost isn't that it might not be apparent what THIS is. The cost is
that THIS is not actually a reasonable type parameter. It's not the
case that you can parameterize a type-instance of the superclass on any
other type that is a subtype of the superclass. Instead, you've
invented the whole thing because it exhibits one piece of convenient
behavior.
My objection is that there is really no justified principle on which
such a type is valid. It's being created only for coincidental
syntactic benefits, at the expense of reasonable programming practices.
The technique is just that used by Enum put together with that used by
StringBuilder. If you wish to avoid StringBuilder and Enum, then good luck.
But it's not! Enum really IS logically parameterized on the specific
enumerated type, and so isn't a comparable example. StringBuilder
doesn't abuse generics at all. Though its ad hoc return-myself
technique is still questionable, it doesn't hurt anyone so badly because
it doesn't change the nature of the StringBuilder type.
In any case, I think we all know where we've gotten from the philosophy
of "if the core API does it, it can't be that bad."
--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.
Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation