Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!news.glorb.com!peer01.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!post01.iad.highwinds-media.com!fx11.iad.POSTED!not-for-mail From: Daniel Pitts User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Thunderbird/24.1.1 MIME-Version: 1.0 Newsgroups: comp.lang.java.programmer Subject: Re: can this be done with generics? References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Lines: 86 Message-ID: X-Complaints-To: abuse@newsrazor.net NNTP-Posting-Date: Sat, 07 Dec 2013 17:04:21 UTC Date: Sat, 07 Dec 2013 09:04:20 -0800 X-Received-Bytes: 3835 X-Received-Body-CRC: 81184600 Xref: csiph.com comp.lang.java.programmer:26769 On 11/24/13 4:55 PM, Andreas Leitgeb wrote: > I'd like to use the "call methods in a chain" pattern > across a class-subhierarchy, with most of the methods > defined in the base-class. > > Suppose, I had two classes: > > class Foo { > public Foo foo1() { > /* do something very interesting ... */ > return this; > } > // assume there were like 100 such foo#() methods here > // (in practice they of course have more diverse names) > } > class Bar extends Foo { > public Bar bar() { > /* do something very interesting */ > return this; > } > } > > And then, somewhere else: > > // the single-class chain works just fine: > new Foo().foo1().foo42().foo84(); > > // but if I start with a Bar, and eventually after some foo#() calls > // want to call method bar() which is not in Foo, then I'm out of luck: > new Bar().foo1().foo42().foo84().bar(); // doesn't work, of course! > > Is there a way to use *generics* for the methods of class Foo such that > each foo#() returns the *static* type on which the compiler saw it > applied? > > Alternatives, that do NOT satisfy me: > a) use an explicit cast to (Bar) > ((Bar)(new Bar().foo1().foo42().foo84())).bar(); > Would turn into a nightmare, when more of Bar's > methods got mixed into the chain. > b) override each of the 100 foo#()s in Bar with a Bar return-type. > Would turn into a nightmare, when more sub-classes like Bar > appeared, or new methods added to Foo. > (Note, that "bad performance" due to extra calls is NOT my concern here) > c) add "Foo bar() { return this; }" in Foo. > Would turn into a nightmare, when more sub-classes like Bar > appeared (and Foo would have to reflect all subclasses' methods), > or some chain accidentally called a subclass method on a chain > started from some other class's instance, and compiler wouldn't > detect the mistake. > > I'm pretty sure, that this would be principially possible (as in: the > compiler has all the information that would be needed), but I can't seem > to find an approach for how to capture the static type of the expression > on which the (non-static) method is called. > > Thanks in advance! > Yes, this *can* be done with generics, but its relatively ugly and hard to maintain. I've been doing a lot of work in PHP lately, and they have a return type hint "@return $this", which makes my IDE of choice recognize the intent. Java, though superior in many ways, is lacking that kind of ability. To answer your question though: abstract class Foo> { public T foo1() { return getThis(); } protected abstract T getThis(); } class Bar extends Foo { public Bar bar1() { /* something interesting */ return this; } protected T getThis() { return this; } } It gets uglier if you need multiple levels of inheritance, or if you have two classes which refer to each other.