yegor256 / cactoos

Object-Oriented Java primitives, as an alternative to Google Guava and Apache Commons
https://www.cactoos.org
MIT License
737 stars 163 forks source link

Type ambiguity in `iterable.Joined` ctors #1600

Open andreoss opened 3 years ago

andreoss commented 3 years ago

Joined has two constructors with the same erasure.

     Joined(final Iterable<? extends T>... items) // erases ctor below when called with 1 argument
     Joined(final Iterable<Iterable<? extends T>> items) { 

Example:

final Iterable<? extends Iterable<Integer>> xxs = new ListOf<Iterable<Integer>>(new ListOf<>(1, 2, 3));
final Iterable<Integer> joined = new Joined<>(xxs); // does not compile
andreoss commented 3 years ago

@victornoel Proposal is to extract from this class 1) Prepended 2) Appended and remove vararg ctor

victornoel commented 3 years ago

@andreoss I experimented a bit and changing public Joined(final Iterable<Iterable<? extends T>> items) to public Joined(final Iterable<? extends Iterable<? extends T>> items) should solve the problem. Would that be enough or do you see other problems?

andreoss commented 3 years ago

@victornoel I don't think so. After erasurej Joined(Iterable<X>) and Joined(Iterable<Iterable<X>) will be the same thing.

victornoel commented 3 years ago

@andreoss maybe I misunderstood the subject you are talking about.

This is what I understand:

So now, even after applying the fix I propose (test it, your code will compile, at least in Eclipse), we only have one problem left that I can see: the ambiguity. When I write new Joined<>(xxs) without expliciting the receiving type (Iterable<Integer> joined in your example), do I mean calling the first vararg constructor or the second one?. The eclipse compiler decides it's the second one even though I could have meant to use the first vararg constructor to get Iterable<Iterable<Integer>> joined.

If I call new Joined<>(new ListOf<>(1, 2, 3)) the compiler correctly infers that I meant to use the first vararg constructor btw.

But in practice, I don't see it happening, because you are always assigning a new Joined to something, so the compiler will know.

Am I missing something here? Do you have examples of problematic code (once you applied the fix I propose).

victornoel commented 3 years ago

@andreoss any feedback on the above?

andreoss commented 3 years ago

@victornoel Yes, the problem is compile time only. I wanted to suggest to remove vararg ctor, or move it to another class. But if wildcard solves that, it's fine. WIll make a PR.

victornoel commented 3 years ago

@0crat assign @andreoss

victornoel commented 3 years ago

@andreoss by the way, what about this? Was there a PR in the end?