If a builder class is always going to be extended, you can fix this.
public class BaseClass<R extends BaseClass<R>> {
@SupressWarnings("unchecked")
public R setBaseStuff() {
/* ... */
return (R)this;
}
}
ugly? Yah. Kinda. It works surprisingly well for the end-user
(builders are almost never assigned to a variable or returned, so even
if there's a class in the builder hierarchy that can be both used
directly and extended, the end-user still won't have a funky
BaseClass<BaseClass> in his code, and I don't know how you make your
builders, but my builders are almost invariably created by calling a
static method on the class I'm building, so that people don't even
have to import the builder. When static classes are involved, they can
handle the funky generics.
On the library side, it's ugly. No way I can come up with excuses
there :)
If you want to eliminate the supresswarnings, and your hierarchy is
strict (leaf nodes are final, non-leaf nodes are abstract) you can,
with some additional ugliness:
protected abstract R getThis();
With all leaf nodes becoming: public class Leaf extends NonLeaf<Leaf>
{ protected Leaf getThis() { return this;} /* code */ }
On Feb 14, 5:14 am, Jeff Grigg <[email protected]> wrote:
> After listening to recent episodes, I've been working my way back to
> earlier episodes, and I keep tripping over discussions of Matthias
> Ernst's "Chaining: A Modest Language Proposal" -- which would make the
> compiler enable a method chaining / "fluid interface" convention on
> methods returning the void type.
>
> I'm also somewhat bothered by the idea of reinterpreting void return
> types, but I think it will be helpful to consider the cases where
> usage would be simplified or fixed by his proposal. So I posted two
> code examples on my blog:
>
> http://jeffgrigg.wordpress.com/2009/02/14/method-chaining-good-for-java/
>
> Briefly, given these two "Builder" classes:
> public class Base {
> public Base setBaseStuff() { /* ... */ return this; }
> }
> public class Sub extends Base {
> public Sub setSubStuff() { /* ... */ return this; }
> }
> This code works:
> new Sub().setSubStuff().setBaseStuff();
> But this code doesn't compile:
> new Sub().setBaseStuff().setSubStuff();
>
> The problem is that when you use method chaining on classes that
> extend other classes and which add methods, you MUST always call
> subclass methods before calling superclass methods -- otherwise it
> won't compile. In non-trivial examples, it gets harder and harder for
> the class' users to follow these rules.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "The
Java Posse" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/javaposse?hl=en
-~----------~----~----~----~------~----~------~--~---