constructor with more than 255 params

T

Thomas Hawtin

Thomas G. Marshall phlegmed up:
Thomas Hawtin coughed up:


Why?

abstract class Supertype {
private boolean something;
public Supertype something(boolean something) {
this.something = something;
return this;
}
}
class Subtype extends Supertype {
private boolean somethingElse;
public Subtype somethingElse(boolean somethingElse) {
this.somethingElse = somethingElse;
return this;
}
}
....
Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // <-- Oops!

abstract class Supertype<THIS extends Supertype> {
private boolean something;
public THIS something(boolean something) {
this.something = something;
return this;
}
}
class Subtype extends Supertype<Subtype> {
private boolean somethingElse;
public Subtype somethingElse(boolean somethingElse) {
this.somethingElse = somethingElse;
return this;
}
}
....
Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // Fine.

Tom Hawtin

[Followup-To: comp.lang.java.programmer]
 
T

Thomas G. Marshall

Thomas Hawtin coughed up:
Thomas G. Marshall phlegmed up:
Thomas Hawtin coughed up:
....[rip]...

abstract class Supertype {
private boolean something;
public Supertype something(boolean something) {
this.something = something;
return this;
}
}
class Subtype extends Supertype {
private boolean somethingElse;
public Subtype somethingElse(boolean somethingElse) {
this.somethingElse = somethingElse;
return this;
}
}
...
Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // <-- Oops!


Gotcha.

....[rip]...
 
R

Roedy Green

...
Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // <-- Oops!

You would have to keep recasting back to (Subtype) which would destroy
the elegance of the idiom.
 
C

Chris Smith

Thomas Hawtin said:
You run into a problem with subtypes when returning this. One solution,
from Java 5.0, is to give an abstract base class a generic type
parameter for the derived class (class Base<THIS extends Base>) and use
the generic parameter for return types.

I hope this is just a fluke. Stuff like that is EXACTLY the sort of
problem people rightly worried about with the introduction of generics
into a language. What you've got is the use of the type system to
cosmetically support a questionable programming idiom... the only
benefit of which is to save the typing of a reference name several
times. In return for this dubious benefit, you are CHANGING THE
FUNDAMENTAL NATURE OF THE TYPE!

I can't count how many good programming techniques this violates. In
any case, we could start with encapsulation, abstraction, and separation
of interface from implementation. Is the functionality of the Base type
really parameterized on its subclass? Of course not! The ONLY reason
for that type parameter is to allow you to avoid doing different things
in different statements.

If I never again see someone demonstrate code like this, it will be too
soon.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
T

Thomas G. Marshall

Chris Smith coughed up:
I hope this is just a fluke. Stuff like that is EXACTLY the sort of
problem people rightly worried about with the introduction of generics
into a language. What you've got is the use of the type system to
cosmetically support a questionable programming idiom... the only
benefit of which is to save the typing of a reference name several
times. In return for this dubious benefit, you are CHANGING THE
FUNDAMENTAL NATURE OF THE TYPE!

I can't count how many good programming techniques this violates. In
any case, we could start with encapsulation,

not sure of that. The only things exposed are things that would have been
exposed anyway by simply accessing the subtype.
abstraction,

agree with that
and separation of interface from implementation.

Mostly agree with that. The point was to make the interface seemlessly
access the polymorphised object without intrusive casts.

Is the functionality of
the Base type really parameterized on its subclass? Of course not!
The ONLY reason for that type parameter is to allow you to avoid
doing different things in different statements.

If I never again see someone demonstrate code like this, it will be
too soon.

Whoa now, easy.

I'm not sure he was particularly /advocating/ this technique, but he was
pointing out the issue at hand and a solution if it was truly a requirement
(for whatever odd reason). Like you said, you hope this is a fluke.

Mucking with types in such questionable compound ways sends shivers up my
spine as well, but I'm betting that Thomas Hawtin thinks so too.
 
T

Thomas Hawtin

Chris said:
I hope this is just a fluke. Stuff like that is EXACTLY the sort of

Calm down!
problem people rightly worried about with the introduction of generics
into a language. What you've got is the use of the type system to

A duplicate of the concerns about dynamic polymorphism.
cosmetically support a questionable programming idiom... the only

After Alan, it's all cosmetic.
benefit of which is to save the typing of a reference name several
times. In return for this dubious benefit, you are CHANGING THE


FUNDAMENTAL NATURE OF THE TYPE!

I'm not changing the fundamental nature of anything. 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 can't count how many good programming techniques this violates. In
any case, we could start with encapsulation, abstraction, and separation
of interface from implementation. Is the functionality of the Base type

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.

Separation of interface from implementation - The technique works fine
even with Java interfaces.
really parameterized on its subclass? Of course not! The ONLY reason

It would be if a clone-like method was implemented...
for that type parameter is to allow you to avoid doing different things
in different statements.

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.
If I never again see someone demonstrate code like this, it will be too
soon.

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 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.

Tom Hawtin
 
R

Raymond DeCampo

Thomas said:
You run into a problem with subtypes when returning this. One solution,
from Java 5.0, is to give an abstract base class a generic type
parameter for the derived class (class Base<THIS extends Base>) and use
the generic parameter for return types.

Couldn't you just override the method in the subclass with the subclass
as the return type since Java 1.5 lets you make a return type more
specific on an overridden method? (I'm not saying this is ideal, just a
little better than mucking with generics.)
It's a bit pointless to have set on every method. It's going to be a bit
obvious what is going on. Better off without the clutter. Particularly
if you have a separate builder class. There's no need to make the
original class mutable - either have a separate builder with a create
method or pass an arguments object to the target class constructor.

Tom Hawtin


Ray
 
T

Thomas G. Marshall

Raymond DeCampo coughed up:
Couldn't you just override the method in the subclass with the
subclass as the return type since Java 1.5 lets you make a return
type more specific on an overridden method? (I'm not saying this is
ideal, just a little better than mucking with generics.)

Well, the item it's modifying is still private, so you'd have to use super,
and it looks less gross to me, but analyzing this stuff is starting to make
me dizzy:


Using Tom Hawtin's example:

static abstract class Supertype {
private boolean something;
public Supertype something(boolean something) {
this.something = something;
return this;
}
}

static class Subtype extends Supertype {
private boolean somethingElse;

public Subtype something(boolean something) {
super.something(something);
return this;
}

public Subtype somethingElse(boolean somethingElse) {
this.somethingElse = somethingElse;
return this;
}
}

....

Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // <-works


--
I've seen this a few times--Don't make this mistake:

Dwight: "This thing is wildly available."
Smedly: "Did you mean wildly, or /widely/ ?"
Dwight: "Both!", said while nodding emphatically.

Dwight was exposed to have made a grammatical
error and tries to cover it up by thinking
fast. This is so painfully obvious that he
only succeeds in looking worse.
 
H

Hemal Pandya

Thomas said:
...
Subtype subtype = new Subtype()
.something(true)
.somethingElse(true); // Fine.

Very cool. But I can't get it to compile without casting the return
value to (THIS). Besides, it gets quite messy with a second level of
inheritance (SSCCE at the bottom).

Given that a class can have only one superclass, I don't have to do any
of this if I am willing to burden the users with knowing the order in
which the methods have to be called. If not, co-variance too provides
an alternative, albeit verbose.

class C0<THIS extends C0> {
public THIS f0() {return (THIS) this;}
}

class C1<THIS extends C1> extends C0<C1<THIS>> {
public THIS f1() {return (THIS) this;}
}

class C2<THIS extends C2> extends C1<C2<THIS>> {
public THIS f2() {return (THIS) this;}
}

class Check {
void foo() {
new C2<C2>().f1().f2();
new C2<C2>().f0().f1();
new C2<C2>().f0().f1().f2();
}
}
 
T

Thomas Hawtin

Hemal said:
Very cool. But I can't get it to compile without casting the return
value to (THIS). Besides, it gets quite messy with a second level of
inheritance (SSCCE at the bottom).

Oops. Yup you need that cast, or do it once in a getThis method.

Tom Hawtin
 
T

Thomas G. Marshall

Thomas Hawtin coughed up:
Oops. Yup you need that cast, or do it once in a getThis method.

Tom Hawtin

Are there any java obfuscation awards out there?

<quote>
class C1<THIS extends C1> extends C0<C1<THIS>> {
public THIS f1() {return (THIS) this;}
}
</quote>

Crimeny!

--
Puzzle: You are given a deck of cards all face down
except for 10 cards mixed in which are face up.
If you are in a pitch black room, how do you divide
the deck into two piles (may be uneven) that each
contain the same number of face-up cards?
Answer (rot13): Sebz naljurer va gur qrpx, qrny bhg
gra pneqf naq syvc gurz bire.
 
C

Chris Smith

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
 
T

Thomas Hawtin

Thomas said:
Thomas Hawtin coughed up:



Are there any java obfuscation awards out there?

<quote>
class C1<THIS extends C1> extends C0<C1<THIS>> {
public THIS f1() {return (THIS) this;}
}
</quote>

Crimeny!

Just to make it clear, that isn't a quote of me. It also does not
represent anything I have suggested.



The getThis method can be implemented with, IMO, little obfuscation.

abstract class MyBaseBuilder<THIS extends MyBaseBuilder> {
protected abstract THIS getThis();
...
}

public class MyDerivedBuilder extends MyBaseBuilder<MyDerivedBuilder> {
protected MyDerivedBuilder getThis() {
return this;
}
...
}

Look, clean client code and no casts!

Tom Hawtin
 
A

Andrew McDonagh

Thomas said:
snipped....
...
}

Just to make it clear, that isn't a quote of me. It also does not represent anything I have suggested.
Tom Hawtin

I don't care who said what,when or why.... I just don't believe we are
still discussing this thread - the entire notion of a constructor
'MANDATING' 250-odd parameters is barking mad.

Can we stop trying to solve a bad design with sticking plaster
suggestions and fix the actual problem - the bad design.

To the OP (Jim) can you explain to us, why you think you need such a
long parameter list - then each person who has offered good-natured
advice, can then offer you the much needed advice of how to improve your
design.

Andrew
 
C

Chris Smith

Thomas Hawtin said:
The getThis method can be implemented with, IMO, little obfuscation.

abstract class MyBaseBuilder<THIS extends MyBaseBuilder> {
protected abstract THIS getThis();
...
}

public class MyDerivedBuilder extends MyBaseBuilder<MyDerivedBuilder> {
protected MyDerivedBuilder getThis() {
return this;
}
...
}

Or:

abstract class MyBaseBuilder
{
protected abstract MyBaseBuilder getThis();
...
}

public class MyDerivedBuilder extends MyBaseBuilder
{
protected MyDerivedBuilder getThis()
{
return this;
}
...
}

As I explained elsewhere, this is using generics for something other
than real parameterized types, and the result is unnecessary complexity.
Fortunately, it's also completely unnecessary.

Furthermore, this means I can still use a reference of type
MyBaseBuilder and can get all the type information that's expected of
it. It also makes it possible to write a sane subclass of
MyDerivedBuilder, something that's completely missing in your example.

Chances are, there are a lot of other more rational behaviors of doing
this the right way. The point is that it IS the right way. It makes
sense within the type system. Abusing generics for this purpose does
not make sense, and as a result it is not correct and it only works by
coincidence. If you didn't anticipate some use in advance, it's just as
likely to fail as succeed.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
T

Thomas Hawtin

Chris said:
But it's not! Enum really IS logically parameterized on the specific
enumerated type, and so isn't a comparable example.

I fail to see the distinction. Other than for Comparable, the only use
of the generic parameter in Enum is to *declare the return type* of the
getDeclaringClass method. To me that is bang on the same thing I am
suggesting. You could even make your builders Comparable if you wanted.
(clone could have returned this instead of throwing. Not sure why they
didn't declare it to return a Void.)
StringBuilder
doesn't abuse generics at all.

What you mean to say is that certain implementations, such as Sun's, do
not use this technique. It would be perfectly valid for
AbstractStringBuidler/StringBuilder/StringBuffer to be implemented using
this technique. Potentially that would be a bad thing as you might not
spot StringBuffer failing to override methods.
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.

There isn't anything ad hoc about it's use of a very common builder
idiom. Suggesting that there is the slightest bit of controversy over
the return this idiom for builders on languages without with blocks,
seems plain unreasonable.

Tom Hawtin
 
T

Thomas Hawtin

Chris said:
Or:

abstract class MyBaseBuilder
{
protected abstract MyBaseBuilder getThis();

Why would you do that? It doesn't seem to achieve anything.
It also makes it possible to write a sane subclass of
MyDerivedBuilder, something that's completely missing in your example.

In general, any non-leaf class should be abstract (I was going to put
final on my derived class but I wouldn't usually do so and the line
wrapped, so I didn't bother). My non-generic derived class behaves
exactly the same as yours with respect to subclassing (with the
exception that your return types are inconsistent).

Tom Hawtin
 
T

Thomas G. Marshall

Andrew McDonagh coughed up:
I don't care who said what,when or why.... I just don't believe we
are still discussing this thread - the entire notion of a constructor
'MANDATING' 250-odd parameters is barking mad.

LOL. A voice of reason decends upon us...

Can we stop trying to solve a bad design with sticking plaster
suggestions and fix the actual problem - the bad design.

These are not really plaster suggestions for the OP: they quickly took on a
life of their own. I suppose the OP might have died at his keyboard and no
one would have noticed ;)

To the OP (Jim) can you explain to us, why you think you need such a
long parameter list - then each person who has offered good-natured
advice, can then offer you the much needed advice of how to improve
your design.

I've asked already, and have had no response.
 
A

Andrew McDonagh

Thomas said:
I suppose the OP might have died at his keyboard and no
one would have noticed ;)
:)



I've asked already, and have had no response.

I'm beginning to think it was a smallTalker or Generics-is-best troll,
trolling us

;-)
 
C

Chris Smith

Thomas Hawtin said:
Why would you do that? It doesn't seem to achieve anything.

I agree. I fail to see the point of "getThis" anyway. I assumed it was
just a dumb example chosen to avoid the need for irrelevant non-trivial
code. However, the code I posted achieved exactly the same thing as the
code you posted.
In general, any non-leaf class should be abstract (I was going to put
final on my derived class but I wouldn't usually do so and the line
wrapped, so I didn't bother).

That's a tad draconian, and still beside the point. The point is that
because you're doing it WRONG, any non-trivial extension beyond what you
might have already predicted has about a 50% chance of breaking. You
seem to have chosen to ignore the other example I gave of this fact.
My non-generic derived class behaves
exactly the same as yours with respect to subclassing (with the
exception that your return types are inconsistent).

You seem to be missing that Java 1.5 implements covariant return types.
My example, in fact, is far more flexible in the case that the
MyDerivedBuilder class has a subclass.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top