Lots of constructors and methods in cactoos take Iterable, Scalar, Func and so on.
Because of the way typing works in Java, it can sometimes be challenging to have code compile even though it is conceptually sound. For example if we have a method or a constructor like this:
void method(Iterable<Scalar<Number>> numbers) { ... }
Then the following happens;
List<LengthOf> list = new ListOf<>(new LengthOf("some text"));
method(list); // does not compile because the types does not exactly match
method(new ListOf<>(new LengthOf("some text")); // compile because the correct type is inferred
In more complex situation, type inference does not even succeed.
The typical solution is to ensure that when using generics as parameters, then variance should be properly defined. The basic rules is that if a generic type is used in outputs of the interface methods, it should be relaxed w.r.t to its subclasses and if it is an input, then w.r.t. its parent classes. For, the above example, this gives us:
void method(Iterable<? extends Scalar<? extends Number>> numbers) { ... }
Of course this only makes sense if the type parameter is either a non-final class or a generic type from the enclosing class or method.
So every where Iterable, Iterator, Scalar, Callable, Supplier, Func, Proc, BiFunc, BiProc are used we need:
- Iterable<? extends X>
- Iterator<? extends X>
- Scalar<? extends X>
- Supplier<? extends X>
- Callable<? extends X>
- Func<? super X, ? extends Y>
- Proc<? super X>
- BiFunc<? super X1, ? super X2, ? extends Y>
- BiProc<? super X1, ? extends X2>
Let's start by package bytes and go on through all of them one by one in alphabetical order by introducing todos once a package or part of it is done. Let's also add some more tests when it makes sense to validate it compiles correctly.
Lots of constructors and methods in cactoos take
Iterable,Scalar,Funcand so on.Because of the way typing works in Java, it can sometimes be challenging to have code compile even though it is conceptually sound. For example if we have a method or a constructor like this:
Then the following happens;
In more complex situation, type inference does not even succeed.
The typical solution is to ensure that when using generics as parameters, then variance should be properly defined. The basic rules is that if a generic type is used in outputs of the interface methods, it should be relaxed w.r.t to its subclasses and if it is an input, then w.r.t. its parent classes. For, the above example, this gives us:
Of course this only makes sense if the type parameter is either a non-final class or a generic type from the enclosing class or method.
So every where Iterable, Iterator, Scalar, Callable, Supplier, Func, Proc, BiFunc, BiProc are used we need:
Let's start by package bytes and go on through all of them one by one in alphabetical order by introducing todos once a package or part of it is done. Let's also add some more tests when it makes sense to validate it compiles correctly.