Chained call pattern with inheritance, polymorphism and generics...

D

Daniel Pitts

I'm trying to create a chainable call. so that I can do something like
myBuilder.something(createSomething()).something(createAnotherSomething()).other(createAnOther());

This isn't so hard if myBuilder is a concrete type with something()
and other() implemented in that concrete type. However, I'd like to
be able to have that hard work done in a base class. Basically, I
know that the something() is always going to return a reference to
"this", I just don't know the type of "this" beforehand. The only way
I could see to cleanly handle this, is to make a generic abstract
getThis() method that has to be implemented in all the concrete types.

public abstract class BaseBuilder<T extends BaseBuilder<T>> {
Set<Something<T>> common = new HashSet<Something<T>>();
public T something(Something<T> something) {
common.add(something);
return getThis(); // this;
}

protected abstract T getThis();
}

public BobsBuilder extends BaseBuilder<BobsBuilder> {

BobsBuilder getThis() {
return this;
}
}

This gets even more complicated if I have several levels of
inheritance, including some sub-classes of already concrete types.


Anyone have a suggestion for a more elegant solution?
 
B

Ben Phillips

Daniel said:
Anyone have a suggestion for a more elegant solution?

Well, there's always

@SuppressWarnings("unchecked")
public T something ..... {
.....
return (T)this;
}

but you might find the need to @SuppressWarnings icky.

You can make it a bit more hygienic, and avoid suppressing more warnings
than you want to, by making a separate "returnThis()" method:

public T something ..... {
.....
return returnThis();
}

public T other ..... {
.....
return returnThis();
}

@SuppressWarnings("unchecked")
public final T returnThis () {
return (T)this;
}

That quarantines the ickiness in a single method in the base class.

Then there's delegation: a single concrete (even final) type implements
the methods that return "this" and whatever others, but punts to a
delegate passed in by constructor; the delegate is an instance of a
polymorphic type (possibly even an interface type). This separates two
concerns into separate classes -- the polymorphic implementation of all
the variable stuff, and the "this-returning behavior" and possibly some
other constant behaviors.

public final class BaseBuilder<T extends Whatever> {
private final BaseBuilderCore<T> bbc;

public BaseBuilder (BaseBuilderCore<T> bbc) {
this.bbc = bbc;
}

public BaseBuilder something (Object param) {
bbc.something(param);
return this;
}

public BaseBuilder other (Object param1, Object param2) {
bbc.other(param1, param2);
return this;
}

public T build () {
return bbc.build();
}
}

(Note: now parametrized on the type of the thing built, which may not be
necessary. The delegate is likewise parametrized.)

Delegation more generally is *very* useful for dodging certain issues
raised by type parameters.
 
P

Piotr Kobzda

Daniel said:
The only way
I could see to cleanly handle this, is to make a generic abstract
getThis() method that has to be implemented in all the concrete types.

Since your method chaining is based on "this" only, there is no need for
"getThis()" at all.

I would probably simply it casting "this" to T in return of each
/chainable method/ of BaseBuilder, together with suppressing all
unchecked warnings on a class' level. Eventually, to allow the compiler
check other warnings, I would do a single final utility method (private
or protected) performing that cast:

@SuppressWarnings("unchecked")
protected final T thisAsT() {
return (T) this;
}

This gets even more complicated if I have several levels of
inheritance, including some sub-classes of already concrete types.

While "this" is either a type specified by T, or a subclass of T, I see
nothing wrong with inheritance here. Of course, in the latter case,
BaseBuilder's methods are unable to return "this" casted to an actual
object's type. But subclasses are still able to do so when you'd like
to preserve the ability of chaining them as well:

public class BobsChildBuider extends BodsBuilder {

@Override
public BobsChildBuilder something(Something<BodsBuilder> something) {
return (BobsChildBuilder) super.something(something);
}
}

Of course, to make it useful, you have to override all chainable
methods. So it's rather impractical, and likely most of direct
subclasses of a BaseBuilder should be final, or abstract (with passing
some of theirs own type parameters to the base class).


The only problem I can see here is with classes like the following:

public class OtherBuilder extends BaseBuilder<BobsBuilder> { ...

And, in general, there is no way to prevent someone from doing that.

But that's a different scenario than mentioned by you, in which your
original approach is better (of course "getThis()" is definitely not a
right name in such a case, "getT()", or other context depended name
might be used instead).

In your scenario classes extending a BaseBuilder must take care of this
problem by themselves.


BTW -- there are also the RFCs closely related to your problem:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6373386
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6479372


HTH,
piotr
 
D

Daniel Pitts

Since your method chaining is based on "this" only, there is no need for
"getThis()" at all.

I would probably simply it casting "this" to T in return of each
/chainable method/ of BaseBuilder, together with suppressing all
unchecked warnings on a class' level. Eventually, to allow the compiler
check other warnings, I would do a single final utility method (private
or protected) performing that cast:

@SuppressWarnings("unchecked")
protected final T thisAsT() {
return (T) this;
}


While "this" is either a type specified by T, or a subclass of T, I see
nothing wrong with inheritance here. Of course, in the latter case,
BaseBuilder's methods are unable to return "this" casted to an actual
object's type. But subclasses are still able to do so when you'd like
to preserve the ability of chaining them as well:

public class BobsChildBuider extends BodsBuilder {

@Override
public BobsChildBuilder something(Something<BodsBuilder> something) {
return (BobsChildBuilder) super.something(something);
}

}

Of course, to make it useful, you have to override all chainable
methods. So it's rather impractical, and likely most of direct
subclasses of a BaseBuilder should be final, or abstract (with passing
some of theirs own type parameters to the base class).

The only problem I can see here is with classes like the following:

public class OtherBuilder extends BaseBuilder<BobsBuilder> { ...

And, in general, there is no way to prevent someone from doing that.

But that's a different scenario than mentioned by you, in which your
original approach is better (of course "getThis()" is definitely not a
right name in such a case, "getT()", or other context depended name
might be used instead).

In your scenario classes extending a BaseBuilder must take care of this
problem by themselves.

BTW -- there are also the RFCs closely related to your problem:http://bugs.sun.com/bugdatabase/vie...un.com/bugdatabase/view_bug.do?bug_id=6479372

HTH,
piotr

It is intended that T always represents the ThisClass type, but it is
hard to enforce that. That one RFE does seem to be what I'm asking
for. (A covariant return type whose type is that of the most concrete
class of the object.
 
P

Piotr Kobzda

Daniel said:
It is intended that T always represents the ThisClass type, but it is
hard to enforce that.

You right. Under same restrictions it's rather hard than impossible.

Now, the only way I can think of to enforce that is based on reflective
inference of actual type arguments of a base class. It may be performed
one time per each distinct type, so it's performance is not a problem in
general, but it's simply quite complicated...

Do you know any nicer way to enforce that?

That one RFE does seem to be what I'm asking
for. (A covariant return type whose type is that of the most concrete
class of the object.

If you think it's important feature, just vote for it. Maybe we'll see
that in the next generation of Java?... :)


piotr
 
D

Daniel Pitts

The returned value can be declared as interface or abstract class if
you don't have a natural base class. The catch is, you won't be able
to access methods not common to all results.

The problem is, that I *want* to be able to access methods specific to
that type.

Otherwise I would return the abstract base class.
 
L

Lew

Daniel said:
The problem is, that I *want* to be able to access methods specific to
that type.

Otherwise I would return the abstract base class.

Java does support covariant return types. Perhaps you could coerce that into
doing what you want.

Absent the "ThisType" feature one can embed a Class<T> in the class to provide
run-time type information.
 
P

Piotr Kobzda

Lew said:
Java does support covariant return types. Perhaps you could coerce that
into doing what you want.

To benefit from covariant return types, overriding of each /chainable
method/ of a base class is required, which is likely something nobody
wants...
Absent the "ThisType" feature one can embed a Class<T> in the class to
provide run-time type information.

Class<T> is in general useless here.

When a subclass (T) is generic, there is no Class<T> able to represent
it at run-time -- a Class may represent erased version of T only. Thus,
a base class should embed Class<? super T> rather than Class<T> -- which
helps almost nothing (unchecked casts still needed).

In fact, even in a case of non-generic subclasses, having a Class<T>
gives a very small benefits here IMHO.


piotr
 
R

Roedy Green

The problem is, that I *want* to be able to access methods specific to
that type.

Otherwise I would return the abstract base class.

In that case you need to add them to the interface and implement them
with dummies, or else cast to specific classes or interfaces to use
them. I can't think of any other mechanisms that would let you get
at the specific methods.
 
P

Piotr Kobzda

Roedy said:
In that case you need to add them to the interface and implement them
with dummies, or else cast to specific classes or interfaces to use
them.

How? You don't know that specific types before use.
I can't think of any other mechanisms that would let you get
at the specific methods.

What's wrong then with pattern presented by Daniel to achieve that?

Similar pattern is successfully used by Enum (a base class "knows" the
type of its particular subclass). Why then not follow that here too?

I've used that pattern a few times in my own code. And (as I already
told in my previous postings to this thread) I see problem only with
enforcement of the appropriate type argument passed to the base class.
I don't know any other way to enforce that than the already described
one, i.e. checking it at run-time.

Nevertheless, the "pattern" itselve is nice, and useful IMHO. (Of
course, support for "ThisType" directly in the language would be nicer,
but that's definitely not the solution we can use today...)


piotr
 
P

Piotr Kobzda

Piotr said:
Roedy Green wrote:

How? You don't know that specific types before use.

Ah, I see now. You suggest to implement only *all known* builders'
methods by each builder. Well, that's possible, and implementing all
dummies in a base class may even make it not hard to maintain, but it's
far from being as elegant as original Daniel's suggestion. So, I still
prefer it over other ideas.


piotr
 
P

Piotr Kobzda

Piotr said:
To benefit from covariant return types, overriding of each /chainable
method/ of a base class is required, which is likely something nobody
wants...

But! Except that mentioned drawback, there is also possible benefit of
using it. So, somebody may still find it useful.

To demonstrate potential benefits, let's define two short, simple, and
almost alternative test cases (SSAATC ;) ):


Case 1:

abstract class BaseBuilder<T extends BaseBuilder<T>> {

T m1() {
return (T) this;
}

}

class ConcreteBuilder extends BaseBuilder<ConcreteBuilder> {

ConcreteBuilder m2() {
return this;
}

}


Case 2:

abstract class BaseBuilder {

BaseBuilder m1() {
return this;
}

}

class ConcreteBuilder extends BaseBuilder {

ConcreteBuilder m1() {
return (ConcreteBuilder) super.m1();
}

ConcreteBuilder m2() {
return this;
}

}


And define also an example usage for both of this cases:

ConcreteBuilder b = new ConcreteBuilder();
b.m1().m2();


Yes, nothing special so far. But let's see now, how the above sample
usage will look after compilation with each of our test-cases...


Case 1 usage code:
0: new #15; //class ConcreteBuilder
3: dup
4: invokespecial #17; //Method ConcreteBuilder."<init>":()V
7: astore_0
8: aload_0
9: invokevirtual #18; //Method ConcreteBuilder.m1:()LBaseBuilder;
12: checkcast #15; //class ConcreteBuilder
15: invokevirtual #22; //Method
ConcreteBuilder.m2:()LConcreteBuilder;
18: pop


Case 2 usage code:
0: new #15; //class ConcreteBuilder
3: dup
4: invokespecial #17; //Method ConcreteBuilder."<init>":()V
7: astore_0
8: aload_0
9: invokevirtual #18; //Method
ConcreteBuilder.m1:()LConcreteBuilder;
12: invokevirtual #22; //Method
ConcreteBuilder.m2:()LConcreteBuilder;
15: pop


See the difference? Yes, additional cast in 1st case (line 12).


So, the hypothesis is now that in the latter case invocation of m1() may
perform better.

But let's see what exactly happens during each method invocation...

In case 1 m1() of BaseBuilder is invoked directly, and the result is
casted to ConcreteBuilder.

In case 2 m1() of ConcreteBuilder is invoked first, which in turn
invokes m1() of BaseBuilder, and then the result of it is casted to
ConcreteBuilder.


So, total number of casts is equal in both cases, thus they differs with
a single invocation more in a 2nd case only.

But wait. What about reimplementing case 2 a bit?

Let's say, write it like that:

ConcreteBuilder m1() {
super.m1();
return this;
}


After that, there is no cast in 2nd case needed anymore.

So final score is:

1 cast, 1 invocation in 1st case vs. 2 invocations in 2nd case.


Assuming possible inlining of invocations by the JVM, it may most likely
happen that case 2 wins.


Of course, everything depends on the JVM. So the above trivial
comparison may lay very far from reality. But I hope it shows that
there is also possibility to benefit from non-generic covariant return
types use.


FWIW, my preference is still to use generic version. But anyway, now I
have to go to sleep... ;)


piotr
 
D

Daniel Pitts

I can't make any sense of it.


What if I changed it to this:

public class BaseBuilder<T> {
private String something;
public T something(String something) {
this.something = something;
return getChainTarget();
}


protected abstract T getChainLink();
}

public class SpecificBuilder extends BaseBuilder<SpecificBuilder> {

private String other;

public SpecificBuilder other(String other) {
this.other = other;
}

protected SpecificBuilder getChainLink() {
return this;
}
}

SpecificBuilder b = new
SpecificBuilder().something("Hello").other("World!");


This works since something() returns T, which in SpecificBuilder IS
SpecificBuilder.

The problem with my solution is that I can't have:

class MoreSpecificBuilder extends SpecificBuilder {
public void doMore() {
}
protected MoreSpecificBuilder getChainLink() {
return this;
}
}

new MoreSpecificBuilder().something("hello").doMore(); // whoops!

If "something()'s" return type could be "the compile time type of the
reference to this object", a.k.a ThisType, then it would work just
fine. Unfortunately, thats not yet a feature. Makes one long for a
weakly typed language :)
 
P

Piotr Kobzda

Daniel said:
What if I changed it to this:

public class BaseBuilder<T> {
private String something;
public T something(String something) {
this.something = something;
return getChainTarget();

I guess, it should return getChainLink() here.
}

protected abstract T getChainLink();
}

public class SpecificBuilder extends BaseBuilder<SpecificBuilder> {

private String other;

public SpecificBuilder other(String other) {
this.other = other;
}

protected SpecificBuilder getChainLink() {
return this;
}
}

SpecificBuilder b = new
SpecificBuilder().something("Hello").other("World!");


This works since something() returns T, which in SpecificBuilder IS
SpecificBuilder.

The problem with my solution is that I can't have:

Of course you can:
class MoreSpecificBuilder extends SpecificBuilder {
public void doMore() {
}
protected MoreSpecificBuilder getChainLink() {
return this;
}

@Override
public MoreSpecificBuilder something(String something) {
super.something(something);
return getChainTarget();
}

@Override
public MoreSpecificBuilder other(String other) {
super.other();
return getChainLink();
}
}

new MoreSpecificBuilder().something("hello").doMore(); // whoops!

Try it now! :)


piotr
 
D

Daniel Pitts

I guess, it should return getChainLink() here.












Of course you can:


@Override
public MoreSpecificBuilder something(String something) {
super.something(something);
return getChainTarget();
}

@Override
public MoreSpecificBuilder other(String other) {
super.other();
return getChainLink();
}



Try it now! :)

piotr

The point is, I shouldn't have to delegate to super just to return the
same reference as a different type.

While that IS currently the case, I wish it werent.
 
P

Piotr Kobzda

Daniel said:
The point is, I shouldn't have to delegate to super just to return the
same reference as a different type.

While that IS currently the case, I wish it werent.

As already mentioned, you can still achieve that today.

Having a base builder declared as follows:

public abstract class BaseBuilder<T extends BaseBuilder<T>> {

protected abstract T nextBuilder();

public T something(String s) {
return nextBuilder();
}
}


One way to achieve your goal would be:

public abstract class SpecificBuilder<T extends SpecificBuilder<T>>
extends BaseBuilder<T> {

public static final class Instance extends SpecificBuilder<Instance> {

protected Instance nextBuilder() {
return this;
}
}

public T other() {
return nextBuilder();
}
}

public abstract class MoreSpecificBuilder<T extends
MoreSpecificBuilder<T>> extends SpecificBuilder<T> {

public static final class Instance extends
MoreSpecificBuilder<Instance> {

protected Instance nextBuilder() {
return this;
}
}

public T doMore() {
return nextBuilder();
}
}


With the following usage:

new SpecificBuilder.Instance().something("test").other();
new MoreSpecificBuilder.Instance().something("test").other().doMore();


Or use another way (the same as above, but more "classical" approach),
which exactly matches your usage scheme:

public abstract class SpecificBuilderBase<T extends
SpecificBuilderBase<T>> extends BaseBuilder<T> {

public T other() {
return thisBuilder();
}
}

public final class SpecificBuilder extends
SpecificBuilderBase<SpecificBuilder> {

protected SpecificBuilder thisBuilder() {
return this;
}
}

public abstract class MoreSpecificBuilderBase<T extends
MoreSpecificBuilderBase<T>> extends SpecificBuilderBase<T> {

public T doMore() {
return thisBuilder();
}
}

public final class MoreSpecificBuilder extends
MoreSpecificBuilderBase<MoreSpecificBuilder> {

protected MoreSpecificBuilder thisBuilder() {
return this;
}
}


Everything in that "pattern" depends on your needs. When you need
extendability of your concrete builder, you do provide an abstract
specialization with a default final realization as an option, otherwise
you just implement it as final class only (still preserving some
extendability of it in a future via delegation to super).


HTH,
piotr
 
D

Daniel Pitts

As already mentioned, you can still achieve that today.

Having a base builder declared as follows:

public abstract class BaseBuilder<T extends BaseBuilder<T>> {

protected abstract T nextBuilder();

public T something(String s) {
return nextBuilder();
}

}

One way to achieve your goal would be:

public abstract class SpecificBuilder<T extends SpecificBuilder<T>>
extends BaseBuilder<T> {

public static final class Instance extends SpecificBuilder<Instance> {

protected Instance nextBuilder() {
return this;
}
}

public T other() {
return nextBuilder();
}

}

public abstract class MoreSpecificBuilder<T extends
MoreSpecificBuilder<T>> extends SpecificBuilder<T> {

public static final class Instance extends
MoreSpecificBuilder<Instance> {

protected Instance nextBuilder() {
return this;
}
}

public T doMore() {
return nextBuilder();
}

}

With the following usage:

new SpecificBuilder.Instance().something("test").other();
new MoreSpecificBuilder.Instance().something("test").other().doMore();

Or use another way (the same as above, but more "classical" approach),
which exactly matches your usage scheme:

public abstract class SpecificBuilderBase<T extends
SpecificBuilderBase<T>> extends BaseBuilder<T> {

public T other() {
return thisBuilder();
}

}

public final class SpecificBuilder extends
SpecificBuilderBase<SpecificBuilder> {

protected SpecificBuilder thisBuilder() {
return this;
}

}

public abstract class MoreSpecificBuilderBase<T extends
MoreSpecificBuilderBase<T>> extends SpecificBuilderBase<T> {

public T doMore() {
return thisBuilder();
}

}

public final class MoreSpecificBuilder extends
MoreSpecificBuilderBase<MoreSpecificBuilder> {

protected MoreSpecificBuilder thisBuilder() {
return this;
}

}

Everything in that "pattern" depends on your needs. When you need
extendability of your concrete builder, you do provide an abstract
specialization with a default final realization as an option, otherwise
you just implement it as final class only (still preserving some
extendability of it in a future via delegation to super).

HTH,
piotr

Yes, those all *work*, but they're an ugly work-around for a missing
feature. Anyway, I've started working on another project, so I'll
file this away under "Close, but no cigar".

Thanks for all you thoughts Piotr. I hadn't thought of the "Instance"
approach. If I do come back to this, that's probably how I'll do it.
Although, I'd use a factory method instead probably:

SpecificBuilder.create().foo().bar();
 

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,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top