Siegfried
Siegfried

Reputation: 311

How to translate this piece of C# generics to Java

Given the following C# code, how can I translate this to Java?

public class Stop : IComparable<Stop>
{
    public int CompareTo(Stop other) { ... }
}

public class Sequence<T> : IEnumerable<T>
    where T : IComparable<T>
{
    public IEnumerator<T> GetEnumerator() { ... }

    IEnumerator IEnumerable.GetEnumerator() { ... }
}

public class Line<T> : Sequence<T>, IComparable<Line<T>>
    where T : Stop
{
    public int CompareTo(Line<T> other) { ... }
}

I have difficulties translating the definition of class Line to Java. My first attempt would be the following:

public class Line<T extends Stop> extends Sequence<T> implements Comparable<Line<T>> { ... }

However, the compiler reports the following error for extends Sequence<T>:

Error: type argument T is not within bounds of type-variable T

Changing the definition to

public class Line<T extends Comparable<T>> extends Sequence<T> implements Comparable<Line<T>> { ... }

fixes the error, but does not accurately reflect the intent: I want to enforce that all type arguments used with Line must be a sub-type of Stop. Using T extends Comparable<T> would allow arbitrary types that implement the interface.

I do not understand the reason for the error. Is there some way to express this relationship without changing the structure of the types or is this a limitation of Java's generics?

Edit: Visit https://www.onlinegdb.com/S1u9wclnH to see a stripped down version of my attempt.

Upvotes: 1

Views: 99

Answers (1)

Daniel
Daniel

Reputation: 16464

The problem is your definition of class Sequence.

public class Sequence<T> : IEnumerable<T>
    where T : IComparable<T> { ... }

This C# class makes use of the fact that IComparable is contra-variant, so the C# class doesn't require exactly T: IComparable<T>, but is also happy if T is comparable with one of its base classes. Thus the code works even if T is instantiated with a class derived from Stop.

Java does not have declaration-site variance, but use-site variance (wildcards). Your Java Sequence class cannot be instantiated for classes derived from Stop, but your Line class might be. Thus the compiler error.

To fix this, you need to translate C#'s declaration-site variance to Java's wildcards whenever you use Comparable in bounds:

class Sequence<T extends Comparable<? super T>> implements Iterable<T> { ... }

Upvotes: 1

Related Questions