BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>
A class or interface cannot implement or extend from different instantiation of a generic interface. Your Bar
interface is breaking this rule. Let's examine the interface declaration:
static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T>
So, Bar<T>
extends two interfaces:
BaseBar<T, Bar<T>>
Foo<T>
In addition to that, those two interfaces extend from different instantiation of the same interface BaseFoo
.
BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S>
Foo<T> extends BaseFoo<T, Foo<T>>
Those inherited interfaces are eventually also the super interfaces of Bar
interface. Thus your Bar
interface tries to extend from 2 different instantiation of BaseFoo
, which is illegal. Let's understand the reason using a simple example:
// Suppose this was allowed
class Demo implements Comparable<Demo> , Comparable<String> {
public int compareTo(Demo arg) { ... }
public int compareTo(String arg) { ... }
}
then after type erasure, compiler would generate 2 bridge methods, for both the generic method. The class is translated to:
class Demo implements Comparable<Demo> , Comparable<String> {
public int compareTo(Demo arg) { ... }
public int compareTo(String arg) { ... }
// Bridge method added by compiler
public int compareTo(Object arg) { ... }
public int compareTo(Object arg) { ... }
}
So, that results in creation of duplicates bridge method in the class. That is why it is not allowed.
Related videos on Youtube
Gelin Luo
A Java programmer since Year 2000 Author of ActFramework and Rythm Template Engine
Updated on September 15, 2022Comments
-
Gelin Luo over 1 year
This is a simplified version of Java inherited Fluent method return type in multiple level hierarchies.
Given the following code:
public enum X { ; static interface BaseFoo<T, S extends BaseFoo<T, S>> { S foo(); } static interface Foo<T> extends BaseFoo<T, Foo<T>> { void foo1(); } static interface BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S> { S bar(); } static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> { void bar1(); } }
run
javac X.java
I get the error message:X.java:15: error: BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>> static interface Bar<T> extends BaseBar<T, Bar<T>>, Foo<T> { ^
Anyone has any solution?
Disclaim: I am trying to use the pattern to implement the fluent interface across a container class inheritance hierarchy.
Background: to make it easier for people to understand why I need this, here is the story. I want to create a container family:
Traversal
<-Sequence
<-List
. SoTraversal
has a methodTraveral<T> accept(Visitor<T>)
(no PECS for short), this method should always returnthis
after iterating the visitor through the elements. When I have aList
type, I want the method returnList<T>
instead ofTraversal<T>
because I want to make it possible to call something likemyList.accept(v).head(15)
, wherehead(int)
is a method ofList
notTraversal
-
Paul Bellora over 10 yearsSure, I'll have a look later today if no one else takes up the challenge.
-
-
Gelin Luo over 10 yearsI know it is illegal, while what I need is how to resolve or work around it. Come to the case,
Bar<T>
is a type ofFoo<T>
so I suppose the rootBaseFoo<T, Foo<T>>
could be replaced asBaseFoo<T, Bar<T>
, which is the same as another inheritance route viaBaseBar
, isn't it? -
Rohit Jain over 10 years@green No it's not like that. A
List<Number>
is not aList<Integer>
. The convariant relationship between types don't follow while using generics. -
Gelin Luo over 10 yearsThanks Rohit. Anyway to work achieve what I want, ie. a fluent API across a container hierarchy?
-
Rohit Jain over 10 years@green I would have to look into what a Fluent API is. Or you can explain in brief what you are trying to do. May be with some more code.
-
Gelin Luo over 10 yearsSo basically I want create a container family of
Traversal
<-Sequence
<-List
, while there are some method defined to returnthis
to facilitate fluent method call, likemyTrv.map(myMapFunc).filter(myFilterFunc)
, and when your instance is ofList
type, then yourmap()
andfilter()
should return aList
, instead ofTraversal
, so that you can write code likemyLst.map(mapFunc).head(5).append(anotherLst)
, wherehead(n)
andappend(...)
areList
method but notTraversal
method. Java8'sBaseStream
andStream
class use this pattern, but only in one level.