0

The basic idea is that I have an interface that transforms data into different data, and I want to use this interface to transform a specific subset of data.

public static interface Data<D> {
    // transform the data into different data
    <T> Data<T> transform(Function<D,T> transformer);
}

// "Something" that has been labeled
public static interface Labeled {
     String getLabel();
}

// class intended to use the Data<D> interface to transform labeled data specifically
public static class LabeledData<L extends Labeled> implements Data<L> {
    public final L labeledData;
    public LabeledData(L labeledData) {
        this.labeledData= labeledData;
    }

    // of course this will not compile because it does not override 
    // <T> Data<T> transform(Function<D,T> transformer);
    @Override
    public <T extends Labeled> LabeledData<T> transform(Function<L,T> transformer) {
        return new LabeledData<>(transformer.apply(labeledData));
    }
}

Is there anyway to either redeclare Data.transform or rearrange LabeledData to acomplished the desired functionality and flow?

I understand I "could" create LabeledData.transformLabled(...) and define the original transform to somehow cast to LabledData or throw an exception, but that doesn't sound like a very good solution.

I could also pass in a T LabeledData<L extends Labeled, T extends Labeled> but I think that would limit the usage to one trasnform type at a time, unless there is some creative way to do it.

1
  • You might be able to do something like class Data<D, B> { <T extends B> Data<T> transform(Function<D, B> transformer), but I'm not sure that'd work. Commented Oct 27, 2022 at 21:23

1 Answer 1

1

You can add an extra type paramter to Data:

public interface Data<TData, TBound> {
    <TTarget extends TBound> Data<TTarget, TBound> transform(Function<TData, TTarget> transformer);
}

TBound is used as the bound for the method's type parameter, TTarget.

Now the label data class' transform would override the interface method:

public static class LabeledData<TLabel extends Labeled> implements Data<TLabel, Labeled> {
    public final TLabel labeledData;
    public LabeledData(TLabel labeledData) {
        this.labeledData= labeledData;
    }

    @Override
    public <TTarget extends Labeled> LabeledData<TTarget> transform(Function<TLabel, TTarget> transformer) {
        return new LabeledData<>(transformer.apply(labeledData));
    }
}

Notice that if you have a bunch of Data with different TBound types in a list, you cannot apply the same transformation to each of them using e.g. map:

// assume that data1, data2, data3 all have different TBounds
List<Data<String, ?>> list = List.of(data1, data2, data3);

list.stream.map(x -> x.transform(y -> f(y))).toList();

Whatever f(y) returns, this is not type safe to do.

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

Comments

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.