In a real use case there were two different types of sensors that had
a common interface/info to be analyzed.  It took a bit to figure out how to
deal with this.  It certainly wasn't convenient.

Imagine the tuple type hierarchy:

class Base {};
class Derived1 extends Base {};
TStream<Derived1> sDerived1 = ...;  // ingest

class Derived2 extends Base {};
TStream<Derived2> sDerived2 = ...;  // ingest

TStream<Base> sBase = sDerived1.union( sDerived2 );
doAnalytics( sBase );

The union() gets a compilation error because TStream<Derived*> doesn't extend
TStream<Base>.  Std java generics stuff.    A straightforward cast doesn't work;
it requires a bit more convoluted casting.

We could make this much easier for users if we added:
TStream<T>:   
    // typesafe cast a TStream<T> to a TStream<U>
    // compile error if U doesn't extend T
    <U extends T> TStream<U> cast(Class<U> classU);

Then one could write:
TStream<Base> sBase = sDerived1.cast(Base.class).union( 
sDerived2.cast(Base.class) );

Does this seem like the right thing to do?  Alternatives?

Fwiw, the implementation of cast() is trivial once you know what to do:
    <U extends T> TStream<U> cast(Class<U> classU) {
      TStream<?> s = (TStream<?>) this;
      @SuppressWarnings("unchecked")
      TStream<U> u = (TStream<U>) s;
      return u;
    }

Having the cast() as a TStream method makes its use much more convenient as 
compared to having cast() as some static utility method.

I didn't have a need for this but similarly we could add:
TStream<T>:
    // semi-typesafe downcast a TStream<T> to a TStream<U>
    // compile error if U doesn't extend T
    // runtime error if any particular tuple from the TStream<T> isn't a U
    <U extends T> TStream<U> downcast(Class<U> classU);

-- Dale [email protected]

Reply via email to