Skip to content

Commit 89f3218

Browse files
Remove covariance of scan/reduce since consumer/producer are the same <T, T, T>
See #360 (comment)
1 parent a2f04b0 commit 89f3218

File tree

4 files changed

+55
-21
lines changed

4 files changed

+55
-21
lines changed

rxjava-core/src/main/java/rx/Observable.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3021,7 +3021,7 @@ public Observable<T> onErrorReturn(Func1<Throwable, ? extends T> resumeFunction)
30213021
* @see <a href="http://msdn.microsoft.com/en-us/library/hh229154(v%3Dvs.103).aspx">MSDN: Observable.Aggregate</a>
30223022
* @see <a href="http://en.wikipedia.org/wiki/Fold_(higher-order_function)">Wikipedia: Fold (higher-order function)</a>
30233023
*/
3024-
public Observable<T> reduce(Func2<? super T, ? super T, ? extends T> accumulator) {
3024+
public Observable<T> reduce(Func2<T, T, T> accumulator) {
30253025
return create(OperationScan.scan(this, accumulator)).takeLast(1);
30263026
}
30273027

@@ -3166,7 +3166,7 @@ public ConnectableObservable<T> publish() {
31663166
*
31673167
* @see #reduce(Func2)
31683168
*/
3169-
public Observable<T> aggregate(Func2<? super T, ? super T, ? extends T> accumulator) {
3169+
public Observable<T> aggregate(Func2<T, T, T> accumulator) {
31703170
return reduce(accumulator);
31713171
}
31723172

@@ -3227,7 +3227,7 @@ public <R> Observable<R> aggregate(R initialValue, Func2<? super R, ? super T, ?
32273227
* @return an Observable that emits the results of each call to the accumulator function
32283228
* @see <a href="http://msdn.microsoft.com/en-us/library/hh211665(v%3Dvs.103).aspx">MSDN: Observable.Scan</a>
32293229
*/
3230-
public Observable<T> scan(Func2<? super T, ? super T, ? extends T> accumulator) {
3230+
public Observable<T> scan(Func2<T, T, T> accumulator) {
32313231
return create(OperationScan.scan(this, accumulator));
32323232
}
32333233

rxjava-core/src/main/java/rx/operators/OperationScan.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static <T, R> OnSubscribeFunc<R> scan(Observable<? extends T> sequence, R
7070
* @return An observable sequence whose elements are the result of accumulating the output from the list of Observables.
7171
* @see <a href="http://msdn.microsoft.com/en-us/library/hh211665(v=vs.103).aspx">Observable.Scan(TSource) Method (IObservable(TSource), Func(TSource, TSource, TSource))</a>
7272
*/
73-
public static <T> OnSubscribeFunc<T> scan(Observable<? extends T> sequence, Func2<? super T, ? super T, ? extends T> accumulator) {
73+
public static <T> OnSubscribeFunc<T> scan(Observable<? extends T> sequence, Func2<T, T, T> accumulator) {
7474
return new AccuWithoutInitialValue<T>(sequence, accumulator);
7575
}
7676

rxjava-core/src/test/java/rx/CovarianceTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import org.junit.Test;
66

7+
import rx.util.functions.Func2;
8+
79
/**
810
* Test super/extends of generics.
911
*
@@ -21,6 +23,25 @@ public void testCovarianceOfFrom() {
2123
// Observable.<HorrorMovie>from(new Movie()); // may not compile
2224
}
2325

26+
@Test
27+
public void testSortedList() {
28+
Func2<Media, Media, Integer> SORT_FUNCTION = new Func2<Media, Media, Integer>() {
29+
30+
@Override
31+
public Integer call(Media t1, Media t2) {
32+
return 1;
33+
}
34+
};
35+
36+
// this one would work without the covariance generics
37+
Observable<Media> o = Observable.from(new Movie(), new TVSeason(), new Album());
38+
o.toSortedList(SORT_FUNCTION);
39+
40+
// this one would NOT work without the covariance generics
41+
Observable<Movie> o2 = Observable.from(new Movie(), new ActionMovie(), new HorrorMovie());
42+
o2.toSortedList(SORT_FUNCTION);
43+
}
44+
2445
/*
2546
* Most tests are moved into their applicable classes such as [Operator]Tests.java
2647
*/
@@ -34,6 +55,15 @@ static class Movie extends Media {
3455
static class HorrorMovie extends Movie {
3556
}
3657

58+
static class ActionMovie extends Movie {
59+
}
60+
61+
static class Album extends Media {
62+
}
63+
64+
static class TVSeason extends Media {
65+
}
66+
3767
static class Rating {
3868
}
3969

rxjava-core/src/test/java/rx/ReduceTests.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public Integer call(Integer t1, Integer t2) {
2525
assertEquals(6, value);
2626
}
2727

28+
@SuppressWarnings("unused")
2829
@Test
2930
public void reduceWithObjects() {
3031
Observable<Movie> horrorMovies = Observable.<Movie> from(new HorrorMovie());
@@ -41,9 +42,15 @@ public Movie call(Movie t1, Movie t2) {
4142
Observable<Movie> reduceResult2 = horrorMovies.reduce(chooseSecondMovie);
4243
}
4344

45+
/**
46+
* Reduce consumes and produces T so can't do covariance.
47+
*
48+
* https://github.com/Netflix/RxJava/issues/360#issuecomment-24203016
49+
*/
50+
@SuppressWarnings("unused")
4451
@Test
4552
public void reduceWithCovariantObjects() {
46-
Observable<HorrorMovie> horrorMovies = Observable.from(new HorrorMovie());
53+
Observable<Movie> horrorMovies = Observable.<Movie> from(new HorrorMovie());
4754

4855
Func2<Movie, Movie, Movie> chooseSecondMovie =
4956
new Func2<Movie, Movie, Movie>() {
@@ -52,36 +59,33 @@ public Movie call(Movie t1, Movie t2) {
5259
}
5360
};
5461

55-
Observable<Movie> reduceResult = Observable.create(OperationScan.scan(horrorMovies, chooseSecondMovie)).takeLast(1);
56-
57-
//TODO this isn't compiling
58-
// Observable<Movie> reduceResult2 = horrorMovies.reduce(chooseSecondMovie);
62+
Observable<Movie> reduceResult2 = horrorMovies.reduce(chooseSecondMovie);
5963
}
6064

65+
/**
66+
* Reduce consumes and produces T so can't do covariance.
67+
*
68+
* https://github.com/Netflix/RxJava/issues/360#issuecomment-24203016
69+
*/
6170
@Test
6271
public void reduceCovariance() {
63-
Observable<HorrorMovie> horrorMovies = Observable.from(new HorrorMovie());
64-
65-
// do something with horrorMovies, relying on the fact that all are HorrorMovies
66-
// and not just any Movies...
67-
68-
// pass it to library (works because it takes Observable<? extends Movie>)
72+
// must type it to <Movie>
73+
Observable<Movie> horrorMovies = Observable.<Movie> from(new HorrorMovie());
6974
libraryFunctionActingOnMovieObservables(horrorMovies);
7075
}
7176

72-
public void libraryFunctionActingOnMovieObservables(Observable<? extends Movie> obs) {
77+
/*
78+
* This accepts <Movie> instead of <? super Movie> since `reduce` can't handle covariants
79+
*/
80+
public void libraryFunctionActingOnMovieObservables(Observable<Movie> obs) {
7381
Func2<Movie, Movie, Movie> chooseSecondMovie =
7482
new Func2<Movie, Movie, Movie>() {
7583
public Movie call(Movie t1, Movie t2) {
7684
return t2;
7785
}
7886
};
7987

80-
Observable<Movie> reduceResult = Observable.create(OperationScan.scan(obs, chooseSecondMovie)).takeLast(1);
81-
82-
//TODO this isn't compiling
83-
// Observable<Movie> reduceResult2 = obs.reduce(chooseSecondMovie);
84-
// do something with reduceResult...
88+
obs.reduce(chooseSecondMovie);
8589
}
8690

8791
}

0 commit comments

Comments
 (0)