Any reason FuncN is not parametrized on the input type ?
See original GitHub issueCurrent FuncN definition is only parametrized on the result type, loosing type information regarding the input of the call method:
public interface FuncN<R> extends Function {
public R call(Object... args);
}
An implementer will most often cast the parameter in order to process it adequately. Which can be tricky (and ugly) for arrays. For example, when using the varadic overload of CombineLatest, a sequence :: List<Observable<Boolean>> -> Observable<List<Boolean>>
looks like this:
Observable<List<Boolean>> sequence (List<Observable<Boolean>> listOfObservableBools) {
return Observable.combineLatest(listOfObservableBools, new FuncN<List<Boolean>> {
public List<Boolean> call(Object... args) {
Boolean[] = Arrays.copyOf(args, args.length, Boolean[].class); // Ewww
return Arrays.asList(booleans);
}
});
}
It also prevents abstracting over the content type (here Boolean) as erasure disallows something like T[].class. It is thus impossible to implement a generic version of this operator, List<Observable<T>> -> Observable<List<T>>
.
The solution IMHO is to add a type parameter to FuncN representing the type of the input parameter:
public interface FuncN<T, R> extends Function {
public R call(T... args);
}
CombineLatest would go from
public static final <T, R> Observable<R> combineLatest(List<? extends Observable<? extends T>> sources, FuncN<? extends R> combineFunction)
to
public static final <T, R> Observable<R> combineLatest(List<? extends Observable<? extends T>> sources, FuncN<? extends T, ? extends R> combineFunction)
making this (and others usages) possible:
Observable<List<T>> sequence (List<Observable<T>> listOfObservableTs) {
return Observable.combineLatest(listOfObservableTs, new FuncN<T, List<T>> {
public List<T> call(T... args) {
return Arrays.asList(args);
}
});
}
Is there a technical reason for the current state of affair ?
Thanks for your hard work and time !
Issue Analytics
- State:
- Created 9 years ago
- Comments:5 (5 by maintainers)
Answering my own question: As far as I can see, having FuncN non-parametrized on the input type was made to permits using
combineLatest(List..., FuncN)
in the implementations of the multiple parameter versions (combineLatest(Observable<T1>, Observable<T2>, Func2<T1, T2, R>)
,combineLatest(Observable<T1>, Observable<T2>, Observable<T3>, Func3<T1, T2, T3, R>)
… ) through a transformation fromFunc<2|3|4|..., R> to FuncN<R>
looking like this:Indeed in that case the parameters types might be heterogeneous and fallback to the lower denominator type Object, before being cast back to their original type.
Let’s agree to disagree on this. You are trading a lot of complexity for what, some type safety? In this case that is not worth the trouble. Static types are nice when they work, but they are just a means to an end, not a goal you chase at any cost. Like spice & food.