Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / September 2007

Tip: Looking for answers? Try searching our database.

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

Thread view: 
Daniel Pitts - 24 Sep 2007 00:24 GMT
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?
Ben Phillips - 24 Sep 2007 01:56 GMT
> 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.
Piotr Kobzda - 25 Sep 2007 10:10 GMT
> 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
Piotr Kobzda - 25 Sep 2007 10:22 GMT
> BTW -- there are also the RFCs closely related to your problem:

RFEs of course.  :)

piotr
Daniel Pitts - 25 Sep 2007 21:59 GMT
> > The only way
> > I could see to cleanly handle this, is to make a generic abstract
[quoted text clipped - 55 lines]
> 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.
Piotr Kobzda - 27 Sep 2007 16:24 GMT
> 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
Roedy Green - 28 Sep 2007 01:21 GMT
On Sun, 23 Sep 2007 23:24:32 -0000, Daniel Pitts
<googlegroupie@coloraura.com> wrote, quoted or indirectly quoted
someone who said :

> I just don't know the type of "this" beforehand.

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.

see http://mindprod.com/jgloss/interfacevsabstract.html
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Daniel Pitts - 28 Sep 2007 02:04 GMT
On Sep 27, 5:21 pm, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> On Sun, 23 Sep 2007 23:24:32 -0000, Daniel Pitts
> <googlegrou...@coloraura.com> wrote, quoted or indirectly quoted
[quoted text clipped - 5 lines]
> 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.
Lew - 28 Sep 2007 02:28 GMT
> On Sep 27, 5:21 pm, Roedy Green <see_webs...@mindprod.com.invalid>
> wrote:
[quoted text clipped - 11 lines]
>
> 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.

Signature

Lew

Piotr Kobzda - 28 Sep 2007 09:05 GMT
> 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
Piotr Kobzda - 29 Sep 2007 02:23 GMT
>> 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...

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
Roedy Green - 28 Sep 2007 09:08 GMT
On Fri, 28 Sep 2007 01:04:57 -0000, Daniel Pitts
<googlegroupie@coloraura.com> wrote, quoted or indirectly quoted
someone who 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.

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

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Piotr Kobzda - 28 Sep 2007 09:57 GMT
> On Fri, 28 Sep 2007 01:04:57 -0000, Daniel Pitts
> <googlegroupie@coloraura.com> wrote, quoted or indirectly quoted
[quoted text clipped - 8 lines]
> 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
Piotr Kobzda - 28 Sep 2007 20:42 GMT
>> 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.

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
Roedy Green - 29 Sep 2007 02:57 GMT
>What's wrong then with pattern presented by Daniel to achieve that?

I can't make any sense of it.
Signature

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Daniel Pitts - 29 Sep 2007 07:24 GMT
On Sep 28, 6:57 pm, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:

> >What's wrong then with pattern presented by Daniel to achieve that?
>
> I can't make any sense of it.
> --
> Roedy Green Canadian Mind Products
> The Java Glossaryhttp://mindprod.com

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 :-)
Piotr Kobzda - 29 Sep 2007 07:57 GMT
>>> What's wrong then with pattern presented by Daniel to achieve that?
>> I can't make any sense of it.
[quoted text clipped - 6 lines]
>        this.something = something;
>        return getChainTarget();

I guess, it should return getChainLink() here.

>     }
>
[quoted text clipped - 21 lines]
>
> 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
Daniel Pitts - 29 Sep 2007 20:02 GMT
> >>> What's wrong then with pattern presented by Daniel to achieve that?
> >> I can't make any sense of it.
[quoted text clipped - 63 lines]
>
> 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.
Piotr Kobzda - 30 Sep 2007 14:16 GMT
> 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
Daniel Pitts - 30 Sep 2007 18:24 GMT
> > The point is, I shouldn't have to delegate to super just to return the
> > same reference as a different type.
[quoted text clipped - 102 lines]
> 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();


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.