2

Given a class Foo and a class Bar extends Foo, it seems as though it should be safe to cast an Observable<Bar> to an Observable<Foo>Observables are read-only, aren't they? But there doesn't seem to be any out-of-the box way to do it without warnings, other than something like

Observable<Bar> barObservable = ...
Observable<Foo> fooObservable = barObservable.map(Foo.class::cast);
// or: Observable<Foo> fooObservable = barObservable.cast(Foo.class);

which compiles without errors, but seems as though it will incur extra method call overhead unless the compiler is very clever.

Other libraries like vavr.io have built-in narrow() methods that at least suppress the warning for you, the equivalent of:

@SuppressWarnings("unchecked")
public static <T> Observable<T> narrow(Observable<? extends T> o) {
  return (Observable<T>) o;
}

But RxJava2 doesn't seem to provide such methods, which makes me wonder if I'm missing something and it's not as safe as I think.


ETA: As (relatively) clean as map(Foo.class::cast) / cast(Foo.class) looks, I've realized it's preferable to write

barObservable.map(b -> (Foo) b);

as this will give you a compilation error if Bar cannot be cast to Foo.

(It won't help with generics, though; you'll just get an unsafe cast warning. For generics, the custom narrow() implementation above seems more type-safe.)

David Moles
  • 48,006
  • 27
  • 136
  • 235
  • The method you provided is the way to do it. `narrow()` may provide a wrapper around that, with error messages, etc. – Bob Dalgleish Mar 16 '18 at 16:17
  • 1
    Java's type system does not support such conversion without warning. There is a [proposal](http://openjdk.java.net/jeps/300) to support co- and contravariance more directly, but since RxJava is targeting version 6, it can't benefit from such enhancements. – akarnokd Mar 17 '18 at 09:09
  • @akarnokd it's a warning because the programmer knows more than the compiler about whether it's safe, and `@SuppressWarnings` exists for the case where the programmer knows it's safe but the compiler can't tell. vavr.io provides `narrow()` as part of the library because they know it's safe and they want to relieve programmers of the burden of having to suppress their own warnings everywhere. What I'm asking is whether it is in fact safe in the RxJava2 context. – David Moles Mar 17 '18 at 15:48

1 Answers1

0

Observable has a cast operator.

StackOverthrow
  • 1,158
  • 11
  • 23
  • It does, so that's an alternative to `map(Foo.class::cast)`, but it's not type-safe (and is in fact less type-safe than `map(b -> (Foo) b)` -- see my update to the question). – David Moles Mar 16 '18 at 19:53