BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>

10,131

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.

Share:
10,131

Related videos on Youtube

Gelin Luo
Author by

Gelin Luo

A Java programmer since Year 2000 Author of ActFramework and Rythm Template Engine

Updated on September 15, 2022

Comments

  • Gelin Luo
    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. So Traversal has a method Traveral<T> accept(Visitor<T>) (no PECS for short), this method should always return this after iterating the visitor through the elements. When I have a List type, I want the method return List<T> instead of Traversal<T> because I want to make it possible to call something like myList.accept(v).head(15), where head(int) is a method of List not Traversal

    • Paul Bellora
      Paul Bellora over 10 years
      Sure, I'll have a look later today if no one else takes up the challenge.
  • Gelin Luo
    Gelin Luo over 10 years
    I 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 of Foo<T> so I suppose the root BaseFoo<T, Foo<T>> could be replaced as BaseFoo<T, Bar<T>, which is the same as another inheritance route via BaseBar, isn't it?
  • Rohit Jain
    Rohit Jain over 10 years
    @green No it's not like that. A List<Number> is not a List<Integer>. The convariant relationship between types don't follow while using generics.
  • Gelin Luo
    Gelin Luo over 10 years
    Thanks Rohit. Anyway to work achieve what I want, ie. a fluent API across a container hierarchy?
  • Rohit Jain
    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
    Gelin Luo over 10 years
    So basically I want create a container family of Traversal <- Sequence <- List, while there are some method defined to return this to facilitate fluent method call, like myTrv.map(myMapFunc).filter(myFilterFunc), and when your instance is of List type, then your map() and filter() should return a List, instead of Traversal, so that you can write code like myLst.map(mapFunc).head(5).append(anotherLst), where head(n) and append(...) are List method but not Traversal method. Java8's BaseStream and Stream class use this pattern, but only in one level.