4

By this answer https://stackoverflow.com/a/1759565/11217621, I know in Java it is possible to do something like

public class MyClass<S, T> {
   public        void foo(Set<S> s, Set<T> t); //same type params as on class
   public <U, V> void bar(Set<U> s, Set<V> t); //type params independent of class
}

where <U, V> for the bar method are independent from the class parametric type.

I have a simple data class in Java like

public class DataPoint<T> {

    public long timeStampMs;
    public T value;

    public <R> DataPoint<R> withNewValue(R newValue){
        return new DataPoint(this.timeStampMs, newValue);
    }

    public KeyedDataPoint withKey(String key){
        return new KeyedDataPoint(key, this.timeStampMs, this.value);
    }
}

...in such way that from an original DataPoint<Long>, I apply some mapping function to the value field, and the value turns into a Double. By using the method withNewValue there is no problem to instantiate a new DataPoint<Double>

public DataPoint<Double> map(DataPoint<Long> dataPoint) {
    double phase = (double) currentStep / numSteps;
    return dataPoint.withNewValue(phase);
}

I need to migrate this to Scala, and I can't figure out how to do it. I'm trying to do something like:

class DataPoint[T1] (val timeStampMs: Long, val value: T1) {
    def withNewValue(value: T2): DataPoint[T2] = new DataPoint[T2](this.timeStampMs, value)
    def withKey(key: String): KeyedDataPoint[T1] = new KeyedDataPoint(key, this.timeStampMs, this.value)
}

...which does not compile. Also tried several combinations following the official documentation about Scala covariance and contravariance but I'm still in my first steps with Scala.

2
  • 2
    If you declare your first method as withNewValue[T2] and add a definition of KeyedDataPoint, then your example seems to compile just fine, without any variance annotations. Not sure what the actual problem is. Commented Mar 17, 2019 at 20:38
  • Thank you Andrey, that worked! Commented Mar 18, 2019 at 17:30

1 Answer 1

3

You're only missing the type parameter [T2] on withNewValue:

class DataPoint[T1] (val timeStampMs: Long, val value: T1) {
    def withNewValue[T2](value: T2): DataPoint[T2] = new DataPoint[T2](this.timeStampMs, value)
    def withKey(key: String): KeyedDataPoint[T1] = new KeyedDataPoint(key, this.timeStampMs, this.value)
}

Compiles just fine.

Sign up to request clarification or add additional context in comments.

8 Comments

Thanks Markus, I could not find anywhere on the Internet how to do it :) By the way, do you know if there is any specific term to refer this, I could not find anything out there by looking up just "type variance" or "generics"
@diegoruizbarbero "type parameters"? If the list with the type parameters is not there, then the type parameter T2 is unavailable.
@diegoruizbarbero Yeah, "type parameters" is the term you are looking for. What's <T> in Java is [T] in Scala - with a slightly different syntax.
I got the syntax for [T] as in <T> ...but what was confusing me was the: public <R> DataPoint<R> withNewValue(R newValue). If DataPoint<R> is the new (second) return type of the function, what is the first <R> in <R> DataPoint<R>? is there a term for that?
@diegoruizbarbero To clarify, these two are completely disjunct, and there is only one return type: DataPoint<R>. The <R> declares that the function contains a parametric type (which is USED in the return type in this case). That's why imo the syntax of Scala makes more sense, because the type parameter is defined similary to normal parameters instead of "somewhere in front of the method" like in Java. Think: def myFunc[... type parameters...](... value parameters...)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.