tag:blogger.com,1999:blog-19776843.post1794992149011092338..comments2019-03-28T08:15:17.348-07:00Comments on Life, Programming, Everything: Java Solutions: inheriting chain callsVlad Patryshevhttp://www.blogger.com/profile/13466586996802181998noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-19776843.post-7763394753247805962011-06-09T20:23:00.695-07:002011-06-09T20:23:00.695-07:00Ran, not that I fully agree with you or fully unde...Ran, not that I fully agree with you or fully understand all the arguments, but, well, you are right.<br /><br />I've come up lately with a better solution, and will post it soon (probably in the end of June).<br /><br />In short, it amounts to defining self() in A:<br /><br />T self() {<br /> return (T) this;<br />}Vlad Patryshevhttps://www.blogger.com/profile/13466586996802181998noreply@blogger.comtag:blogger.com,1999:blog-19776843.post-65570864176639480732008-12-31T15:10:00.000-08:002008-12-31T15:10:00.000-08:00This is really clever, but then instances of B are...This is really clever, but then instances of <B>B</B> are not instances of <B>A</B>; that is, there's no IS-A relationship between <B>B</B> and <B>A</B>. (In more formal terms, you've gained implementation inheritance but lost type inheritance.) This means that a client method designed to accept an instance of <B>A</B> cannot be used with an instance of <B>B</B>.<BR/><BR/>(I'm assuming that we consider this to be a problem. If we have no desire for instances of <B>B</B> to be instances of <B>A</B>, then I guess that's fine, but I think it's a pretty ugly restriction.)<BR/><BR/>Now, the client method can be written to accept an instance of <B>SuperA<?></B> instead of <B>A</B>, and everything will work fine. The only problem is, it won't be able to use the method chaining you've worked so hard for, because every method's return type will be the unrestricted wildcard!<BR/><BR/>You can solve this partly by declaring your classes more restrictively — instead of <B>class SuperA<T></B>, it could be <B>class SuperA<T extends SuperA<? extends T>></B> (and so on) — Java's type-capture rules are smart enough to apply recursively, so that you could then write <B>sa.do1("").do2("").do1("")</B> where <B>sa</B> is an expression of type <B>SuperA<?></B> — but you're still complicating your type hierarchy, and requiring clients to be aware of what's basically an implementation detail. Any class that wants to create a new instance of <B>A</B> will need to be aware of <B>A</B> so it can call its constructor, and any class that wants to perform operations on instances of <B>A</B> will want to be aware of <B>SuperA</B> so it can still work on instances of <B>B</B> (as well as other, as-yet-unknown subtypes).<BR/><BR/><EM>That</EM>, you can partly solve by changing <B>SuperA</B>, <B>A</B>, <B>SuperB</B>, and <B>B</B> to <B>A</B>, <B>A.Concrete</B>, <B>B</B>, and <B>B.Concrete</B> (respectively), making the concrete classes be private static member classes of their supertypes, and having clients create instances by calling a static <B>A.newInstance()</B> (which would be declared as type <B>A<?></B>) instead of calling a constructor directly (and likewise for subclasses).<BR/><BR/>And you end up with a heck of a lot of dense boilerplate code, plus you've forced your clients to write <B>A<?></B> everywhere (providing a wildcard type argument representing an implementation detail that from their perspective serves no purpose whatsoever), which works fine but is kind of silly.<BR/><BR/>Also, remember when I said that Java's type-capture rules are smart enough for that? Well, they are, but there might be down-sides. Eclipse 3.3.2 (which we use at my workpace) is smart enough to apply these rules to distinguish legal code from illegal code, but when you type <B>a.do1("").</B> and it gives you a list of applicable methods, some sort of internal exception seems to get thrown (and caught) internally: it doesn't even list all the methods belonging to <B>Object</B>. (But I don't know how other versions of Eclipse behave, much less how other IDEs do.)<BR/><BR/>All told, I'm not sure how often it's worth it to take this sort of approach, rather just overriding methods and delegating to the superclass. (Keeping in mind that this whole thing is a patch over one small, specific problem: a method that doesn't exist in class <B>A</B> can't be chained to a method that's not overridden in class <B>B</B>.)Ranhttps://www.blogger.com/profile/01369980917358096502noreply@blogger.comtag:blogger.com,1999:blog-19776843.post-44551640782943678912008-12-12T22:34:00.000-08:002008-12-12T22:34:00.000-08:00Thanks; link fixed.Thanks; link fixed.Vlad Patryshevhttps://www.blogger.com/profile/13466586996802181998noreply@blogger.comtag:blogger.com,1999:blog-19776843.post-40370024953412271842008-12-12T14:36:00.000-08:002008-12-12T14:36:00.000-08:00hey, first link is brokenhey, first link is brokenSergey Malginhttps://www.blogger.com/profile/11626056894508064419noreply@blogger.com