On Wed, 8 Nov 2023 17:11:39 GMT, Rémi Forax <fo...@openjdk.org> wrote:
>> The API should be client-friendly, not implementor-friendly, given that it's >> expected to have much more clients than implementors. An implementor can >> easily delegate to a private method to add missing type parameters. I did >> exactly this in the >> [teeing](https://github.com/openjdk/jdk/blob/7d25f1c6cb770e21cfad8096c1637a24e65fab8c/src/java.base/share/classes/java/util/stream/Collectors.java#L1913) >> Collector before. There should not be a reason to expose a parameter, which >> is merely an implementation detail. This also complicates the public >> documentation of the already complex feature, specifying the parameter which >> is not necessary to specify. >> >>> Has this proven to be a problem for things like >>> [Collectors.mapping(…)](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Collectors.html#mapping(java.util.function.Function,java.util.stream.Collector)) >>> ? >> >> I'm not sure how I can prove this, given that you don't usually know the >> downstream accumulator, so if somebody hits this problem, they will be >> forced to solve it in another way (e.g., extracting parts of complex >> collector to separate variables), so you won't find the code in the wild >> which uses `mapping` type arguments explicitly. Yes, `Collectors.mapping` >> and `groupingBy` did this mistake in the past, and there's no reason to >> repeat it again. >> >>> Do you have a concrete example of where the current "encoding" causes a >>> caller-problem? >> >> For example, I want to create a reusable gatherer that performs scan-concat >> and wraps every resulting string with '[...]'. First try: >> >> >> var gatherer = Gatherers.scan(() -> "", String::concat) >> .andThen(Gatherer.ofSequential((_, t, pusher) -> >> pusher.push(STR."[{t}]"))); >> >> >> Now, the type of `gatherer` is `Gatherer<String, ?, Object>`, but I want >> `Gatherer<String, ?, String>`. I have the following alternatives: >> 1. Specify the variable type explicitly: >> >> Gatherer<String, ?, String> gatherer = Gatherers.scan(() -> "", >> String::concat) >> .andThen(Gatherer.ofSequential((_, t, pusher) -> >> pusher.push(STR."[{t}]"))); >> >> 2. Specify `ofSequential` type arguments: >> >> var gatherer = Gatherers.scan(() -> "", String::concat) >> .andThen(Gatherer.<String, String>ofSequential((_, t, pusher) -> >> pusher.push(STR."[{t}]"))); >> >> 3. Specify the types of lambda arguments explicitly: >> >> var gatherer = Gatherers.scan(() -> "", String::concat) >> .andThen(Gatherer.ofSequential((Void _, String t, Downstream<? super >> String> pusher) ->... > > I agree with Tagir here, it should be an ? and if you want to capture it in a > type variable you can use the standard trick of having the private method > declaring the type variable and the public method with the wildcard calling > the private method. Sold! Type argument removed! ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/16420#discussion_r1387774512