On Wed, 8 Nov 2023 15:23:39 GMT, Viktor Klang <vkl...@openjdk.org> wrote:

>> This is especially important given that often you don't know the AA type at 
>> all. E.g., imagine that you are doing `.andThen(Gatherers.fold(...))`, but 
>> `fold` returns `Gatherer<T, ?, R>`, so you can specify explicit `RR`, but 
>> not `AA`.
>
> 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))
>  ? 🤔 
> 
> There's one implication on turning it into a wildcard—it may actually cause 
> issues implementing the composition directly in the override, as you won't 
> have a typename to refer to.
> 
> Do you have a concrete example of where the current "encoding" causes a 
> caller-problem?

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) -> pusher.push(STR."[{t}]")));

4. Specify `.andThen` type arguments:

var gatherer = Gatherers.scan(() -> "", String::concat)
    .<Void, String>andThen(Gatherer.ofSequential((_, t, pusher) -> 
pusher.push(STR."[{t}]")));

In all the cases, I need to specify explicitly more types than I need, as I 
need to specify only `String`. If we remove `AA`, then specifying `andThen` 
type arguments would be the shortest and the most readable alternative:


var gatherer = Gatherers.scan(() -> "", String::concat)
    .<String>andThen(Gatherer.ofSequential((_, t, pusher) -> 
pusher.push(STR."[{t}]")));

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/16420#discussion_r1386952517

Reply via email to