constructor with more than 255 params

C

Chris Smith

Thomas Hawtin said:
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.

The entire intent is different. In Enum, the parameterized type is
intended to ensure that one can hold a reference of the supertype
Enum and use it in a normal, reasonable way... namely, that
Enum<?>.getDeclaringClass returns an instance of Class<?>, while
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.

No, it wouldn't! I thought you were just arguing against the importance
of rational design -- but now I see that you are entirely missing the
point. The existence of a type parameter on a type is NOT an
implementation detail. It's one of the most fundamental possible
aspects of the declared interface of a type. You can't add it without
breaking the specification for the behavior of these classes. For
similar reasons, you can't add it to your own classes where it doesn't
belong, without messing up the distinction between interface and
implementation.
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.

Unreasonable or not, it's a clever hack. It isn't at all relevant to
the point of the code, and it requires additional knowledge about the
return type of the method that isn't obvious from the code. It's only
existence is a tiny with of convenience.

Now, I'm not complaining. Since the sensible return type for these
append methods is void, it's not hurting anyone to return this instead.
Smalltalk, in fact, makes this such a common idiom that it's basically
expected... and yet I have nothing against Smalltalk. If people like
it, then fine. There's nothing negative about my saying it's a clever
hack, but it's still a clever hack.

That doesn't change the fact that it's nothing but a clever hack. If
you have to introduce substantial complexity and weak abstractions to
the code to support it, then it's not so clever any longer, and it has
no place.

(Fortunately, you don't have to add such complexity to the code. You'd
do yourself a favor by learning about covariant return types in Java
1.5.)

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

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

Thomas Hawtin

Chris said:
Thomas Hawtin said:
[Christ Smith wrote: ]
[Thomas Hawtin wrote: ]
abstract class MyBaseBuilder
{
protected abstract MyBaseBuilder getThis();

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.

The reason is spread across a few posts. It's just there so that methods
can return 'this' in the type expected by the client code. Your code
most certainly does not achieve this purpose.
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

That must be a meaning of the word wrong that I was not previously
familiar with.
might have already predicted has about a 50% chance of breaking. You

The different approaches work THE SAME with respect to extensions. What
point are you stumbling on?
seem to have chosen to ignore the other example I gave of this fact.

Sorry, I missed that.
You seem to be missing that Java 1.5 implements covariant return types.

Not at all. Covariant return types are not helpful if you don't want to
be forced into overriding methods only to get the type system to play ball.
My example, in fact, is far more flexible in the case that the
MyDerivedBuilder class has a subclass.

Absolute rubbish. My MyDerivedBuilder class can have subclasses just as
easily as yours.

Tom Hawtin
 
C

Chris Smith

Thomas Hawtin said:
The reason is spread across a few posts. It's just there so that methods
can return 'this' in the type expected by the client code. Your code
most certainly does not achieve this purpose.

Okay, I've looked and I still fail to see any reason for a getThis()
method other than the one I mentioned... to avoid putting irrelevanty
dummy code into the method for example purposes. Obviously, with a
getThis method in real life:

<e>.getThis()

could be replaced by:

<e>

for any possible non-null expression <e>.

Nevertheless, it's still the case that your code doesn't accomplish
anything that mine doesn't.
Not at all. Covariant return types are not helpful if you don't want to
be forced into overriding methods only to get the type system to play ball.

Where did the new requirement (no overriding methods) come from? Did I
miss that from earlier in the thread?

Overriding the method is, of course, how you use covariant return types.
Adding a pointless type parameter is how you use generics to do this.
Of course you can't do either without doing it. That goes without
saying.

I must say, though, given the choice between overriding a method or
screwing up the public interface of a type, I'd rather override a
method.
Absolute rubbish. My MyDerivedBuilder class can have subclasses just as
easily as yours.

But your MyDerivedBuilder subclass will have a method that returns
MyDerivedBuilder. With covariant return types, a further subclass can
return a more specific type. (Of course, you could apply covariant
returns to a subclass of your MyDerivedBuilder as well, but then you
REALLY have no answer to the question of why you screwed up the API in
the first place.)

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

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

Thomas Hawtin

Chris said:
No, it wouldn't!

Checking an example with javap, I concede javac does not produce binary
compatible code (I haven't checked through the specs).
For
similar reasons, you can't add it to your own classes where it doesn't
belong, without messing up the distinction between interface and
implementation.

The purpose of adding the generic parameter is to provide a sensible
interface. I would like to do this without adding huge quantities of cut
and paste code.
Now, I'm not complaining. Since the sensible return type for these
append methods is void, it's not hurting anyone to return this instead.
Smalltalk, in fact, makes this such a common idiom that it's basically
expected... and yet I have nothing against Smalltalk. If people like
it, then fine. There's nothing negative about my saying it's a clever
hack, but it's still a clever hack.

Yeah, returning this is a hacky idiom, IMO. It's not adding any further
hackyness to make the idiom work with polymorphism. The entire point of
generics is to get static typing and polymorphism to work together.
That doesn't change the fact that it's nothing but a clever hack. If
you have to introduce substantial complexity and weak abstractions to
the code to support it, then it's not so clever any longer, and it has
no place.

The alternative is to either have messy client code or introduce a mini
language. While mini languages can be great, I'd much keep stuff that
Java is equipped to deal with in Java (with all the goodness that entails).
(Fortunately, you don't have to add such complexity to the code. You'd
do yourself a favor by learning about covariant return types in Java
1.5.)

I'm sorry. I find it disingenuous of you to accuse me of not knowing
about covariant return types in Java whilst replying to a post of mine
using covariant return types in Java.

Tom Hawtin

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

Thomas Hawtin

Chris said:
Okay, I've looked and I still fail to see any reason for a getThis()
method other than the one I mentioned... to avoid putting irrelevanty
dummy code into the method for example purposes. Obviously, with a

It's a protected method, so it isn't about eliding functionality from a
public method. It's just there for the public methods to be able to
return the correct type.
getThis method in real life:

<e>.getThis()

could be replaced by:

<e>

for any possible non-null expression <e>.

Not true. The point is that it returns a type of the required type. You
cannot replace this.getThis() with this.
Nevertheless, it's still the case that your code doesn't accomplish
anything that mine doesn't.




Where did the new requirement (no overriding methods) come from? Did I
miss that from earlier in the thread?

The requirement not to be forced into massive copy & paste operations
(and subsequent maintenance hell), I would hope is pretty basic axiom of
almost any software development task. You disagree?
But your MyDerivedBuilder subclass will have a method that returns
MyDerivedBuilder. With covariant return types, a further subclass can
return a more specific type. (Of course, you could apply covariant
returns to a subclass of your MyDerivedBuilder as well, but then you
REALLY have no answer to the question of why you screwed up the API in
the first place.)

Yes, my example gets to do exactly the same covariant return types as yours.

Exactly how you implement polymorphic, return-this builders will depend
on the situation. We can take it down different routes. If I want to
encourage subclassing, I'll take it down that route. If subclassing does
not happen, I'll take a different route. If there will be some
subclassing, then take aspects of the other routes.

Tom Hawtin
 
H

Hemal Pandya

Thomas said:
Thomas said:
Are there any java obfuscation awards out there?
[....]

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

Without the so-called obfuscation, any class that further extends the
branch cannot be used as a builder.
 
C

Chris Smith

Thomas Hawtin said:
Checking an example with javap, I concede javac does not produce binary
compatible code (I haven't checked through the specs).

Of course, this avoids the point. The javap application does not
faithfully reproduce the exposed API of a type, since it ignores
generics even in 1.5. It only exposes the implementation and the type
erasure of the API. Since I am telling you that your implementation
fails to expose a reasonable API by adding a pointless type parameter,
using javap isn't going to help shed any light on the matter.
The purpose of adding the generic parameter is to provide a sensible
interface. I would like to do this without adding huge quantities of cut
and paste code.

The purpose is to support a hack, at the expense of a substantially
weaker abstraction. The hack has nothing whatsoever to do with the
purpose of the code. It just happens to have a convenient side-effect.

As I said elsewhere, I like convenient side-effects. But whenever they
conflict with good abstraction, abstraction has to win.
The alternative is to either have messy client code or introduce a mini
language. While mini languages can be great, I'd much keep stuff that
Java is equipped to deal with in Java (with all the goodness that entails).

I'm not sure where the mini-language came from. While it would indeed
be possible to introduce a new language here, it is certainly easier to
just fix the problem while working in Java. The solution looks like
this in general-purpose code:

A a = new A();

a.doFirstThing();
a.doSecondThing();

or in a superclass constructor parameter:

super(buildA());

...

private static A buildA()
{
A a = new A();

a.doFirstThing();
a.doSecondThing();

return a;
}

Hardly too awfully messy, nor is there a mini-language involved. To
some people (like me) it is clearer and obviously advantageous over
chaining a bunch of unrelated operations together into one expression.
I'm sorry. I find it disingenuous of you to accuse me of not knowing
about covariant return types in Java whilst replying to a post of mine
using covariant return types in Java.

No, I was under the impression that you weren't aware of covariant
return types when I wrote that. I now know that you are, but you reject
them for reasons that aren't clear to me.

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

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

Chris Uppal

Chris said:
Smalltalk, in fact, makes this such a common idiom that it's basically
expected...

The idiom (method call chaining) is indeed built into Smalltalk, and you'll see
it used a lot in old[*] code, but many[**] Smalltalkers consider it to be
sloppy programming -- choosing an abbreviated form that is fragile and not at
all intent-revealing.

I dislike the idiom even /more/ in Java. "Disgusting" is about the right word.

-- chris

(

[*] One possible reason, which was more valid then than now, is that the idiom
also reduces the amount of stack pushing/popping. I doubt if the difference is
even measurable now (I haven't tried) but it might have been significant back
in the '80s)

[**] "many" == a group of indeterminate size, but which includes me ;-)

)
 
T

Thomas Hawtin

Chris said:
Thomas Hawtin said:
[Chris Smith wrote: ]
No, it wouldn't!

Checking an example with javap, I concede javac does not produce binary
compatible code (I haven't checked through the specs).


Of course, this avoids the point. The javap application does not
faithfully reproduce the exposed API of a type, since it ignores
generics even in 1.5. It only exposes the implementation and the type
erasure of the API. Since I am telling you that your implementation
fails to expose a reasonable API by adding a pointless type parameter,
using javap isn't going to help shed any light on the matter.

The type parameter would not be exposed to the public. Just the same as
my example code.

The point of using javap was to establish binary compatibility. In FCS
versions of Java 1.5.0 it isn't, although looking back it appears to
have been fine in the Java 1.5.0 Release Candidate.
private static A buildA()
{
A a = new A();

a.doFirstThing();
a.doSecondThing();

return a;
}

As a minor point, that's a slightly degenerate builder, in that it
builds itself, rather than producing a product.

Often you will have type and variable names of more than one letter.
Constructing a GUI pane, for instance, could take screen fulls, where
there is no point splitting into methods. Making your example a little
more realistic:

ProductBuilder builder = new ProductBuilder();

builder.firstThing(arg0, arg1, arg2);
builder.secondThing(arg0, arg1, arg2);
...
builder.nthThing(someOtherArg);

return builder.create();

Using the standard idiom, that becomes:

return new ProductBuilder()
.firstThing(arg, arg1, arg2)
.secondThing(arg, arg1, arg2)
...
.nthThing(someOtherArg)
.create()
;

Look at GUI code using GridBagConstraints. Absolute nightmare (even
without its other defects).



Here appears to be your real problem. You can't stand the common,
widespread idiom for builder usage. Given that you aren't going to
accept that, it's not likely you are going to take to anything involving
the idiom. Your hangup.

Tom Hawtin
 
R

Roedy Green

ProductBuilder builder = new ProductBuilder();

builder.firstThing(arg0, arg1, arg2);
builder.secondThing(arg0, arg1, arg2);
...
builder.nthThing(someOtherArg);

return builder.create();

The advantage of this pattern is you can abort the creation of an
incomplete or inconsistent object. If you used the setters after the
new, there is no guarantee the caller will do enough of them to create
a proper object.

Now, what kind of clever code can go into create to implement this
cleanly?

I presume that ProductBuilder or Product is a subset of the other, and
that you have a way of promoting/demoting without a lot of hard to
maintain code.
 
C

Chris Smith

Roedy Green said:
The advantage of this pattern is you can abort the creation of an
incomplete or inconsistent object. If you used the setters after the
new, there is no guarantee the caller will do enough of them to create
a proper object.

Roedy, can you explain this advantage? Are you just referring to the
fact that there isn't a temporary allocation of the object which then
gets discarded and then garbage collected? If so, are you sure that the
allocation and garbage collection of an extra "builder" object in the
common case doesn't outweigh that benefit?

But you made it sound like there's a correctness issue here. I'm
unclear on what you're saying.

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

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

Thomas Hawtin

Roedy said:
The advantage of this pattern is you can abort the creation of an
incomplete or inconsistent object. If you used the setters after the
new, there is no guarantee the caller will do enough of them to create
a proper object.

I'm not sure what you are getting at here.
Now, what kind of clever code can go into create to implement this
cleanly?

I assume you are taking the piss. But, I see a way to ensure with
chained building that a set of methods are called on the builder without
a type explosion, I think. It would take extreme circumstances to make
it worthwhile, so I'm not going to show it.
I presume that ProductBuilder or Product is a subset of the other, and
that you have a way of promoting/demoting without a lot of hard to
maintain code.

The relationship between Builder and Product is just the bog standard
builder pattern as in the GoF (they happen to use a bit of inheritance
to be all cool and OO).

Some examples of builders in various forms from Java (off the top of my
head) -

java.lang.StringBuilder/StringBuffer -> String
java.awt.GridBagConstraints -> self
java.nio.Buffer -> self/byte[]/file/etc
java.io.ByteArrayOutputStream -> byte[]
java.io.StringOutputStream -> String
java.lang.Appendable -> String
java.lang.ProcessBuilder -> Process
java.util.Calendar -> Date/long

You will have probably seen lots of people's MapBuilders.

<collection> -> Collection.unmodifiable<collection> can be a
builder-product relationship.

Arrays.asList is often used to build Lists (if you consider placing a
value in each component an operation).

java.util.regex.Pattern.compile is essentially a builder relationship
between the mini-language and Pattern. Similarly for other (mini) languages.

Tom Hawtin
 
R

Roedy Green

Roedy, can you explain this advantage?

Compare the builder pattern with something like this:

Dalmatian d = new Dalmatian();

d.setHasShots( true );
d.setWeight ( 20 );
d.setSex ( Gender.MALE );
d.checkConsistency():

Let us say you did not consider a Dalmatian object complete until
those three fields were filled in and some consistency checks were
done.

Somebody not understanding this restriction could create malformed
Dalmatian objects and set them loose on the universe.
e.g.
Dalmatian d = new Dalmatian();
d.setSex ( Gender.MALE );
// and nothing else

With the builder pattern, they can't inadvertently do that.

I am just stating the obvious for the newbies.
 

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
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top