Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic parameter with additional constraint through intersection types

Tags:

java

generics

I am writing a class to represent time series data, i.e. basically a map of (Instant, T) pairs for a generic type T

interface TimeSeries<T> {
     void add(Instant when, T data);
}

Some of the classes we deal with implement an interface

interface TimeStamped {
    Instant getTimeStamp();
}

and I want to provide a more convenient method in the TimeSeries interface to add such data items without stating the time explicity. Basically, I want

interface TimeSeries<T> {
     void add(Instant when, T data);
     default <X extends T & TimeStamped> void add(X data) {
         add(data.getTimeStamp(), data);   
     } 
}

but this seems not allowed by the language because I cannot use type variables in intersection types. Is there a work-around that does not involve giving up static type-safety? The only things I can come up with are

interface TimeSeries<T> {
     void add(Instant when, T data);
     default void add(TimeStamped data) {
         add(data.getTimeStamp(), (T)data);   
     }
     default void add(TimeStamped t, T data) {
         add(t.getTimeStamp(), data);
     } 
}

add(TimeStamped t, T data) is type-safe but still inconvenient.

like image 473
Jens Avatar asked Nov 07 '22 15:11

Jens


1 Answers

I guess I understand your question. Basically, you could have a TimeSeries with some simple type that doesn't implement TimeStamped, but some of its subclasses do. In those cases, not even the workaround by @assylias helps.

Well, I think there is no clean solution for this problem in Java 8, and I have no experience with Java 9, but I didn't notice anything like that while reading about its new features. That means you either sacrifice static type safety or comfort.

It is kinda hard to tell what is the best workaround. Basically what we have here so far is:

  • TimeStamped-only interface for the cases where your base object already implements the TimeStamped interface, as advised by @assylias.
  • Static method as advised by @cppbeginner. I don't like the syntax though, it is meant as syntax sugar, but you end up with a static call. It's quite versatile though and does what you want.
  • Give up on the syntax sugar idea entirely and just type it like a slave.
  • Give up type safety and have a nice code that can backfire.
  • Oh wait, one more possibility. Make it a method of TimeStamped interface instead, with the TimeSeries as an argument. Actually better than going static, but kinda bottom up.

I can't decide which one is better for you as I don't know your use case. None of them is perfect. I already encountered this issue and I found no super-smart solution either. Another thing I was unable to do is a generic enum. I mean, why not, it would be interesting if it was possible (but it's not, either).

like image 173
Vlasec Avatar answered Nov 14 '22 23:11

Vlasec