How to translate this piece of C# generics to Java - 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.

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> { ... }

Related

Intertwined java generic interfaces and classes

I have a very specific problem with java generics. The follwowing classes and interfaces have been predefined:
public interface IFirst<R, T> {...}
public abstract class AbstractFirst<T extends AbstractFirst, L extends IFirst<String, T>> {...}
public interface ISecond extends IFirst<String, AbstractSecond> {...}
public abstract class AbstractSecond extends AbstractFirst<AbstractSecond, ISecond> {...}
Now I've created a following repo definition which seems to be valid:
public abstract class AbstractRepo<T extends AbstractFirst<T, IFirst<String,T>>> {...}
But now that i want to extend it:
public class RepoFirst extends AbstractRepo<AbstractSecond> {...}
I get the following error:
Bound mismatch: The type AbstractSecond is not a valid substitute for the bounded parameter
<T extends AbstractFirst<T,IFirst<String,T>>> of the type AbstractRepo<T>
I cannot change the first four (at least not radically) beacuse they are too heavily ingrained with the rest of the application, but the second two are new and up for change if need be.
Also intrestingly it allows the following (with raw type warnings):
public class RepoFirst extends AbstractRepo {
...
#Override
AbstractFirst someAbstractMethod() {
return new AbstractSecond() {...};
}
...
}
But for code clarity I would like to implement it with clearly defining AbstractSecond as the generic type for Abstract Repo.
What am I missing?
Your AbstractRepo expects an instance of IFirst and not a subtype of IFirst. But your AbstractSecond is clearly not IFirst. (I mean it is, from a OO standpoint but for generics, List<Number> is not the same as List<Integer>). It's ISecond. It might work if you could change your AbstractRepo from IFirst to ? extends IFirst as you did for AbstractFirst.

CRTP and double inheritance

I have the following sets of classes:
public abstract class GSObject<T extends GSObject<T>> {
public abstract boolean matches(String toMatch);
//Other functions
public static <T extends GSObject<T>> T findMatch(List<T> objects, String toMatch){
//Code that iterates through the list, seeing if one matches;
}
}
public abstract class Phrase extends GSObject<Phrase> {
//More code
}
public class Request extends Phrase{
#Override
public boolean matches(String toMatch){
//Implementation of matches()
}
}
Running the following command: Request.findMatch(allRequests,chat); gives the following error:
Bound mismatch: The generic method findMatch(List<T>, String) of type GSObject<T> is not applicable for the arguments (List<Request>, String). The inferred type Request is not a valid substitute for the bounded parameter <T extends GSObject<T>>
If I do Phrase.findMatch(allPhrases, chat); it does not throw an error, meaning that this has to do with double inheritance. Do I have to write another static function that works with a Class that extends a Class that extends GSObject?
I've looked into making GSObject an interface, but it has some classes that I would like to define (not abstractly) in the class.
Is there something I am missing (in any of the three classes), or do I need to create an interface that defines the function matches() (What I am trying to avoid)?
One option is to make Phrase generic in the same way that GSObject is:
public abstract class Phrase<T extends Phrase> extends GSObject<T> {
public class Request extends Phrase<Request> {
This way, Request extends GSObject<Request> (unlike in your code, where Request extends GSObject<Phrase>).
Another option might be to decouple some of these dependent types by using wildcards, e.g. by one of these:
public static <T extends GSObject<T>> T findMatch(List<? extends T> objects, String toMatch){
public static <U extends GSObject<?>> U findMatch(List<U> objects, String toMatch){
though this can be tricky to get right. Note that with this approach, Request will still advertise that it can handle any List<? extends Phrase>, so you lose some of the benefit of the static type system. (In other words, these versions make your classes more permissive than they're really supposed to be.)
A third option is to do both of the above. It does make sense, after all, for Request.findMatch to take a List<? extends Request>.
Without seeing more of your code, it's hard to know which of these makes most sense for your case.

.NET equivalent for Java bounded wildcard (IInterf<?>)?

I'm stuck trying to translate some Java code that uses (bounded) wildcard generics to C#. My problem is, Java seems to allow a generic type to be both covariant and contravariant when used with a wildcard.
[This is a spin-off from a previous question dealing with a simpler case of bounded-wildcards]
Java - works:
class Impl { }
interface IGeneric1<T extends Impl> {
void method1(IGeneric2<?> val);
T method1WithParam(T val);
}
interface IGeneric2<T extends Impl> {
void method2(IGeneric1<?> val);
}
abstract class Generic2<T extends Impl> implements IGeneric2<T> {
// !! field using wildcard
protected IGeneric1<?> elem;
public void method2(IGeneric1<?> val1) {
val1.method1(this);
//assignment from wildcard to wildcard
elem = val1;
}
}
abstract class Generic<T extends Impl> implements IGeneric1<T>, IGeneric2<T> {
public void method1(IGeneric2<?> val2) {
val2.method2(this);
}
}
C# - doesn't compile...
class Impl { }
interface IGeneric1<T> where T:Impl {
//in Java:
//void method1(IGeneric2<?> val);
void method1<U>(IGeneric2<U> val) where U : Impl; //see this Q for 'why'
// https://stackoverflow.com/a/14277742/11545
T method1WithParam(T to);
}
interface IGeneric2<T>where T:Impl {
void method2<U>(IGeneric1<U> val) where U : Impl;
}
abstract class Generic2<T, TU>: IGeneric2<T> //added new type TU
where T : Impl
where TU : Impl
{
//in Java:
//protected IGeneric1<?> elem;
protected IGeneric1<TU> elem;
//in Java:
//public void method2(IGeneric1<?> val1)
public void method2<U>(IGeneric1<U> val)
where U : TU //using TU as constraint
{
elem = val; //Cannot convert source type 'IGeneric1<U>'
//to target type 'IGeneric1<TU>'
}
public abstract void method1WithParam(T to);
}
abstract class Generic<T> : IGeneric1<T>, IGeneric2<T> where T : Impl
{
//in Java:
//public void method1(IGeneric2<?> val2)
public void method1<U>(IGeneric2<U> val2) where U : Impl
{
val2.method2(this);
}
public abstract T method1WithParam(T to);
public abstract void method2<U>(IGeneric1<U> val) where U : Impl;
public abstract void nonGenericMethod();
}
If I change interface IGeneric1<T> to interface IGeneric1<out T> the above error goes away, but method1WithParam(T) complains about variance:
Parameter must be input-safe. Invalid variance: The type parameter 'T' must be
contravariantly valid on 'IGeneric1<out T>'.
Let me start by saying that is definitely starting to look like a design review is in order. The original Java class aggregates an IGeneric1<?> member, but without knowing its type argument there's no possibility to call method1WithParam on it in a type-safe manner.
This means that elem can be used only to call its method1 member, whose signature does not depend on the type parameter of IGeneric1. It follows that method1 can be broken out into a non-generic interface:
// C# code:
interface INotGeneric1 {
void method1<T>(IGeneric2<T> val) where T : Impl;
}
interface IGeneric1<T> : INotGeneric1 where T : Impl {
T method1WithParam(T to);
}
After this, class Generic2 can aggregate an INotGeneric1 member instead:
abstract class Generic2<T>: IGeneric2<T> where T : Impl
{
protected INotGeneric1 elem;
// It's highly likely that you would want to change the type of val
// to INotGeneric1 as well, there's no obvious reason to require an
// IGeneric1<U>
public void method2<U>(IGeneric1<U> val) where U : Impl
{
elem = val; // this is now OK
}
}
Of course now you cannot call elem.method1WithParam unless you resort to casts or reflection, even though it is known that such a method exists and it is generic with some unknown type X as a type argument. However, that is the same restriction as the Java code has; it's just that the C# compiler will not accept this code while Java will only complain if you do try to call method1WithParam1.
Java doesn't allow a type to be both variant and covariant. What you have is an illusion stemming from the fact that while you are declaring IGeneric1<?> elem in the class Generic2, you don't use its method T method1WithParam(T val);; therefore Java don't see any problem with this declaration. It will however flag an error as soon as you will try to use it through elem.
To illustrate this, the following add a function test() to the Generic2 class which will try to call the elem.method1WithParam() function but this leads to a compilator error. The offensive line has been commented out, so you need to re-install it in order to reproduce the error:
abstract class Generic2<T extends Impl> implements IGeneric2<T> {
// !! field using wildcard
protected IGeneric1<?> elem;
public void method2(IGeneric1<?> val1) {
val1.method1(this);
//assignment from wildcard to wildcard
elem = val1;
}
public void test() {
Impl i = new Impl();
// The following line will generate a compiler error:
// Impl i2 = elem.method1WithParam(i); // Error!
}
}
This error from the Java compiler proves that we cannot use a generic type as both covariant and contravariant and this; even if some declaration seems to prove the contrary. With the C# compiler, you don't even have a chance to get that close before getting a compilation error: if you try to declare the interface IGeneric1<T extends Impl> to be variant with IGeneric1<out T extends Impl>; you automatically get a compilation error for T method1WithoutParam();
Second, I took a look at the reference .NET equivalent for Java wildcard generics <?> with co- and contra- variance? but I must admit that I don't understand why this can be seen as a solution. Type restriction such as <T extends Impl> has nothing to do with unbounded wildcard parameterized type (<?>) or variance (<? extends Impl>) and I don't see how replacing the seconds with the first could be seen as a general solution. However, on some occasions, if you don't really need to use a wildcard parameterized type (<?>) or a variance type than yes, you can make this conversion. However, if you don't really use them in your Java code, this one should also be corrected, too.
With Java generics, you can introduce a lot of imprecision but you won't get that chance with the C# compiler. This is especially true considering that in C#, classes and structs are fully reifiable and therefore, do not support variance (both covariance and contravariance). You can use that only for the declaration of an interface and for delegates; if I remember correctly.
Finally, when polymorphism is involved, there is often a bad tendency to use unnecessary generic types; with or without wildcard parameterized types and variance. This often lead to a long and complex code; hard to read and use and even harder to write. I will strongly suggest you to look at all this Java code and see if it's really necessary to have all this stuff instead of a much simpler code with only polymorphism or a combination of polymorphism with generic but without variance or wildcard parameterized type.

Bound mismatch with Java Generics "nesting"

I'm having difficulty using generics for a redesign/refactoring I'm doing on an existing design.
public interface DataDto {
// some data here
}
public interface SetDto<MyDataDto extends DataDto> {
List<MyDataDto> getData();
}
public interface Results<MySetDto extends SetDto<DataDto>> {
MySetDto getResults();
}
public interface MyProblemInterface<MyDataDto extends DataDto,
MySetDto extends SetDto<MyDataDto>,
MyResults extends Results<MySetDto>> {
// some stuff here
}
My problem is that I get the following error for MyProblemInterface:
Bound mismatch: The type MySetDto is not a valid substitute for the
bounded parameter <MySetDto extends SetDto<DataDto>> of the type
Results<MySetDto>
I admit my experience with generics is somewhat limited, but basically I'm trying to enforce that all three of the types in MyProblemInterface are the same "type". For example, if I have ADataDto, BDataDto, ASetDto<ADataDto>, BSetDto<BDataDto>, AResults<ASetDto>, BResults<BSetDto>, I want to ensure a class can't implement MyProblemInterface in a manner like AMyProblemInterface<ADataDto, ASetDto, BResults>. I would think that since MySetDto extends SetDto<MyDataDto> just fine, I could continue to take that further, but I'm apparently wrong.
Thank you for any help.
You want too much from Java generics.
It would be simpler to declare your interface as following:
public interface MyProblemInterface<MyDataDto extends DataDto>
And then force method to use SetDto<MyDataDto> and Results<MySetDto>.
By using generics in class/interface declaration you specify some kind of variety which is determined later in definition. But in your case you said that SetDto and Results will always have MyDataDto as parameter, so there is no variety.
Shouldn't it be something like this instead, and you add the actual classes only when implementing the interfaces.
Updated the code, because I forgot to add the right Results definition. This should work.
public interface DataDto {
// some data here
}
public interface SetDto<T extends DataDto> {
List<T> getData();
}
public interface Results<T extends SetDto<? extends DataDto>> {
T getResults();
}
public interface MyProblemInterface<T extends DataDto, E extends SetDto<T>, K extends Results<E>> {
// some stuff here
}

How to force a generic type parameter to be an interface?

Is there a way in java to specify, that the type parameter of a generic class must be an interface (not just extending it!)
What I want to do is the following:
public class MyClass<X extends SomeInterface, Y extends SomeOtherClass & X>
Meaning that Y must be a subclass of SomeOtherClass AND implement X.
What I currently get by the compiler is
The type X is not an interface; it cannot be specified as a bounded parameter
So, how can I tell the compiler that X must always be an interface?
Edit:
OK, I guess I oversimplified my problem a bit. Let's use my actual application domain to make it more clear:
I have an API for representing diagrams. A Diagram contains Node and Edge objects. All these three classes implement the Shape interface. Shapes may have child shapes, a parent shape and belong to a diagram.
The thing is, that I need to make two versions of this API: one open-source with just basic functionality and an extended one with more features. However, the extended API must only provide methods, which return the extended types (ExtendedDiagram, ExtendedNode, ExtendedEdge and (here comes the problem) ExtendedShape).
So I have something like this:
/* BASIC CLASSES */
public interface Shape<X extends Shape<X,Y>, Y extends Diagram<X,Y>>{
public List<X> getChildShapes();
public X getParent();
public Y getDiagram();
...
}
public class Diagram<X extends Shape<X,Y>, Y extends Diagram<X,Y>> implements Shape<X,Y>{...}
public class Edge<X extends Shape<X,Y>, Y extends Diagram<X,Y>> implements Shape<X,Y>{...}
...
/* EXTENDED CLASSES */
public interface ExtendedShape extends Shape<ExtendedShape,ExtendedDiagram> { ... }
public class ExtendedDiagram extends Diagram<ExtendedShape,ExtenedDiagram> implements ExtendedShape { ... }
public class ExtendedEdge extends Edge<ExtendedShape,ExtenedDiagram> implements ExtendedShape { ... }
...
The extended API works fine and the basic API code gives some warnings, but the main problem occurs when using the basic API:
public class SomeImporter<X extends Shape<X,Y>, Y extends Diagram<X,Y>, E extends Edge<X,Y>>{
private Y diagram;
public void addNewEdge(E newEdge){
diagram.addChildShape(newEdge);
...
That last line gives me the following warning:
The method addChildShape(X) in the type Diagram is not applicable for the arguments (E)
So now, I would just like to specify that E also needs to implement X and all would be fine - I hope ;)
Does all that make sense? Do you guys know a way to do that? Or is there even a better way to get the extended API with the said restrictions?
Thanks for sticking with me, any help is greatly appreciated!
You can use:
class Foo<T extends Number & Comparable> {...}
A class Foo with one type parameter, T. Foo must be instantiated with a type that is a subtype of Number and that implements Comparable.
In the generics context, <Type extends IInterface> handles both extends and implements. Here's an example:
public class GenericsTest<S extends Runnable> {
public static void main(String[] args) {
GenericsTest<GT> t = new GenericsTest<GT>();
GenericsTest<GT2> t2 = new GenericsTest<GT>();
}
}
class GT implements Runnable{
public void run() {
}
}
class GT2 {
}
GenericsTest will accept GT because it implements Runnable. GT2 does not, therefore it fails when trying to compile that second GenericsTest instantiation.
Maybe you can simplify your model a bit: too much generics become quickly a real pain in terms of readability, and that's quite an issue if you define a public API. Usually, if you can't understand anymore what should be inside the brackets, then you're going too far for your need - and you can't expect users to understand it better than yourself...
Anyway, in order to make your code compile, you may try defining something like this, in the Shape type:
public <S extends Shape<?,?>> void addChildShape(S shape);
That should do it.
HTH
You wrote the following:
public interface Shape<X extends Shape<X,Y>, Y extends Diagram<X,Y>>{
public List<X> getChildShapes();
public X getParent();
public Y getDiagram();
...
}
I would advise, at the minimum, getting rid of the X type variable, as follows:
public interface Shape<Y>{
public List<Shape<Y>> getChildShapes();
public Shape<Y> getParent();
public Diagram<Y> getDiagram();
...
}
The reason being is that what you originally wrote suffers from a potentially unbounded recursive nesting of the type parameters. A shape may be nested within a parent shape, which may be nested within another, all of which must be accounted for in the type signature... not a good recipe for readability. Well, it doesn't happen quite that way in your example, in which you declare "Shape<X>" instead of "Shape<Shape<X>>" but that's the direction you're going in, if you ever wanted to actually use Shape on its own...
I would probably also recommend going one step further and getting rid of the Y variable for similar reasons. Java generics don't cope very well with this sort of composition. When attempting to enforce static types for this type of modelling via generics, I've found that the type system starts to break down when you start to extend things later on.
It's typical of the Animal/Dog problem... Animal has a getChildren(), but Dog's children must also be Dogs... Java doesn't cope with this well because (in part due to the lack of abstract types as in languages like Scala, but I'm not saying you should rush off and use Scala for this problem either) the type variables have to start being declared in all sorts of places where they don't really belong.
Use a pre-processor to generate the "reduced" version of your code. Using apt and annotations might be a nice way to do it.
I might be WAY off base here, but my understanding of generics is a little different.
I am asking someone to correct me if I am wrong.
IMO -
This is a very confusing structure that you have. You have SubClasses of Shape being referenced infinitely it looks like.
Your Shape interface is utilized in the same manner as a HashMap, but I have never seen a HashMap do what you are trying to do, eventually you have to have X be a class in Shape. Otherwise you are doing HashMap
If you always want X to be a "IS A" relationship to an interface it won't happen. That is not what generics are for. Generics are used to apply methods to multiple Objects, and interfaces cannot be Objects. Interfaces define a contract between a client and a class. All you can do with the is say that you will accept any Object that implements Runnable, because all or some of your methods are required to utilize the Runnable interface methods. Otherwise if you don't specify and you define as , then your contract between your class with the client can produce unexpected behavior and cause either the wrong return value or an exception to be thrown.
For example:
public interface Animal {
void eat();
void speak();
}
public interface Dog extends Animal {
void scratch();
void sniff();
}
public interface Cat extends Animal {
void sleep();
void stretch();
}
public GoldenRetriever implements Dog {
public GoldenRetriever() { }
void eat() {
System.out.println("I like my Kibbles!");
}
void speak() {
System.out.println("Rufff!");
}
void scratch() {
System.out.println("I hate this collar.");
}
void sniff() {
System.out.println("Ummmm?");
}
}
public Tiger implements Cat {
public Tiger() { }
void eat() {
System.out.println("This meat is tasty.");
}
void speak() {
System.out.println("Roar!");
}
void sleep() {
System.out.println("Yawn.");
}
void stretch() {
System.out.println("Mmmmmm.");
}
}
Now if you did this class you can expect that you CAN always call 'speak()' & 'sniff()'
public class Kingdom<X extends Dog> {
public Kingdom(X dog) {
dog.toString();
dog.speak();
dog.sniff();
}
}
However, if you did this you CANNOT ALWAYS call 'speak()' & 'sniff()'
public class Kingdom<X> {
public Kingdom(X object) {
object.toString();
object.speak();
object.sniff();
}
}
CONCLUSION:
Generics give you the ability to utilize methods on a wide range of objects, not interfaces. Your final entry into a generic MUST be a type of Object.
The reserved word “extends” as along with a type parameter T is used to specify a bound.
‘…in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces).’
[ https://docs.oracle.com/javase/tutorial/java/generics/bounded.html ]
In short, “extends” can only be used to specify a bound (whether a class or an interface) for some class type parameter T and not any interface type parameter T.
In your case,
public class MyClass<X extends SomeInterface, Y extends SomeOtherClass & X>
The compiler resolves X to be a class. For the second occurrence of X along with the type parameter Y (which clearly needs to be a class anyway), it requires X to be an interface. Since it has already resolved X to be class, it signals the error for the second occurrence of X,
The type X is not an interface;
Further, had X been specified in the first occurrence as an unbounded parameter, the compiler would have resolved it to be either a class or an interface and it would’ve considered the second occurrence of X to be a possible interface and thus allowed compilation. Since it was not so, the compiler clarifies,
it cannot be specified as a bounded parameter

Categories

Resources