Yes, I meant the Reader.transferTo(Writer), and no I just did a quick search over the JDK code base and I would to takle them as a second step. I would make a couple of different patches for the various places due the fact that they are in different parts of the JDK…
The question would be if I should proceed with the Reader.transferTo(Writer) together with the static method on Readable.transferTo(Appendable)… -Patrick > Am 19.11.2017 um 23:14 schrieb Brian Goetz <brian.go...@oracle.com>: > > I presume you mean Reader.transferTo(Writer)? This seems fine, and you can > have a much better implementation for Reader->Writer than for > Readable->Appendable. (Do we get patches for those 30 places too?) > > > > On 11/19/2017 3:01 PM, Patrick Reinhart wrote: >> Having a static method on Appendable instead of a default one seem >> reasonable to me too. >> >> Would it be a problem to have an additional transferTo() method on Readable >> as in your overload example though similar to IntputStream? My researches of >> the JDK code base found at least 30 places where a simple transferTo on a >> Reader could have been used to transfer all data to a Writer. Also some less >> usages where a combination of Reader -> CharBuffer or CharBuffer -> >> Appendable could have been used to. This analysis lead to the idea to have a >> default method for those use cases instead may be use a separate static >> method for Readable/Appendable and one on a Reader as on the InputStream >> >> -Patrick >> >> >>> Am 19.11.2017 um 14:42 schrieb Brian Goetz <brian.go...@oracle.com>: >>> >>> Late to this thread, but ... >>> >>> TL;DR: I think this method, as proposed, is fatally flawed; it should be a >>> static method rather than a default method. >>> >>> >>> We need to be very, very careful about adding default methods like this to >>> highly abstract interfaces like Readable (the -able suffix is often the >>> giveaway that you're in murky waters wrt default methods). There are many >>> pitfalls one can run into here; the one that gets us here is that attempted >>> overrides can easily and accidentally become overloads. >>> >>> DIGRESSION -- A LESSON FROM 8 >>> >>> By way of background, we added Function.compose(...) in Java 8, when both >>> functional interfaces and default methods were new, and this turned out to >>> be a mistake. This seemed a no-brainer (in j.l.f.Function), but didn't >>> turn out so well. We added: >>> >>> intf Function<T,U> { >>> <V> Function<T,V> compose(Function<U,V> g); >>> } >>> >>> But note also that >>> >>> intf BinaryOperator<T> extends Function<T,T> { >>> } >>> >>> As such, binOp.compose(binOp) yields a Function<T,T>, not a BinOp<T>. >>> Oops, that's not what we wanted! If we try and override it: >>> >>> intf BinaryOperator<T> extends Function<T,T> { >>> BinaryOperator<T> compose(BinaryOperator<T> g); >>> } >>> >>> we haven't really overridden compose(), but instead we've overloaded it. >>> And now we have potential ambiguities in overload resolution because >>> >>> f.compose(t -> t) >>> >>> is compatible with both overrides of compose(). And since we don't have >>> overloading on return types, we can't even use the return type to >>> disambiguate: >>> >>> BinaryOperator<T> composed = f.compose(t -> t) // nope >>> >>> The siren song here was the desire for fluency; this was just the wrong >>> place to put a compose() method. This method interacted with inheritance >>> in two ways; it could be overridden, and it was also desirable for it to >>> have distinguished behavior for distinguished subtypes of its argument >>> types. This was just too many degrees of freedom, and it painted us into a >>> corner. Function was too general a place to put a default method like >>> compose() that had such potential to interact with inheritance, but we were >>> so excited about the prospects of saying "f.compose(g)" that we didn't >>> think it through. >>> >>> RETURNING TO THE CURRENT ISSUE >>> >>> Now, while you could claim this is not an exact analogy (i.e., transferTo >>> doesn't take a lambda, which was one ingredient of the problems with >>> compose), the reality is that the higher up in the hierarchy you go, the >>> more risky adding defaults is. There still is a big interaction risk here. >>> >>> In this case, the risk is that both Readable and Appendable are "too >>> general." In particular, it means that overriding in a subclass won't mean >>> what you might think it means. Think of the overridings that are actually >>> likely to happen -- those where you know something more about both what >>> kind of Readable and Appendable you've got. >>> >>> Let's say that Reader does: >>> >>> class Reader { >>> long transferTo(Writer out) { ... } >>> } >>> >>> This is a totally sensible thing to want to do, since Writer has more >>> flexibility than Appendable, and so such an implementation could be better >>> than the default. >>> >>> The problem is: **this is not an override, but an overload**. Which means >>> that >>> >>> Reader r = ... >>> Writer.w = ... >>> r.transferTo(w) >>> >>> will not mean the same thing as >>> >>> Readable rr = r; >>> Appendable ww = w; >>> r.transferTo(ww); >>> >>> Because InputStream.transferTo() is not an override of Readable.appendTo(). >>> This is serious puzzler-bait! Instance method dispatch is not supposed to >>> depend on the static types involved, but that's sure what it looks like is >>> happening here. >>> >>> **IMO, this is a fatal API design error for this method**. Instead, >>> Readable.transferTo() should probably be a static method, so that it does >>> not give the illusion of being overridable. >>> >>> I know default methods on highly abstract interfaces are very tempting, and >>> the siren song of fluency calls to us, but we should be very, very careful >>> about adding default methods to interfaces like Iterable or Readable -- >>> essentially any of the Xxxable interfaces. >>> >>> I think it is much better to make this a static method, and put concrete >>> methods (with better implementations, that can take advantage of bulk write >>> abilities, which Appendable lacks) on Reader as needed. (InputStream >>> already has this method.) >>> >>> >>> On 11/17/2017 1:12 PM, Patrick Reinhart wrote: >>>> Hi Roger and Alan, >>>> >>>> I incorporated the latest feedback using version 1) from this latest post: >>>> >>>> http://mail.openjdk.java.net/pipermail/core-libs-dev/2017-November/050004.html >>>> >>>> >>>> The actual webrev is here: >>>> >>>> http://cr.openjdk.java.net/~reinhapa/reviews/8066870/webrev.00 >>>> >>>> >>>> -Patrick >