1

edit: I've made this example far simpler

I want to create a class with a generic parameter which extends a type with a generic parameter X and I want to refer to that type X without declaring it explicitly.

I'm not sure if this answers it too Why can't I use a type argument in a type parameter with multiple bounds?

class Fruit<T> {}

// I don't want to have to redefine T e.g. <F extends Fruit<T>,T>
// because T should be implicit for Fruit (see Example of instance below)
// the below will not compile, but is roughly what I'd like
class Box<F extends Fruit<T>> {
    T get( F fruit ) { return null; }
}

Example of instance

class Apple extends Fruit<String>

// this is what I would like, but this won't compile with above definiton
class AppleBox extends Box<Apple> {
    // String get( Apple apple ) should be implicit
}

I don't want to have to declare

class AppleBox extends Box<Apple,String>

Because String is the only option available here and should be known implicitly

Community
  • 1
  • 1

2 Answers2

0

The scope of the generic type inside the Fruit class is within the class Fruit itself. That generic type variable cannot be accessed outside of the class.

Therefore you must define T to take the place of the generic type, and since you are using the variable T elsewhere, you can't just leave it out either.

So to reiterate the type T in fruit is only visible in type fruit, so to use it in Box, you need to define that type again somewhere:

public class Outer {

  class Fruit<T> {
    T body;
  }

  abstract class Box<F extends Fruit<T>, T> {
    abstract T get( F fruit );
  }
}

If you want T to be implicit to Fruit then don't define the generic parameter T inside the class Fruit, but rather in the outer class.

public class Outer<T> {

  class Fruit {
    T body;
  }

  abstract class Box<F extends Fruit> {
    abstract T get( F fruit );
  }
}

An analogy to this scope problem is the following code:

for (int i = 0; i < 10; i++) {
  // stuff
}
for (int i = 0; i < 20; i++) { // i from previous loop is not visible here
  // stuff
}
System.out.println(i); // variable not defined: i
nmore
  • 2,474
  • 1
  • 14
  • 21
  • The scope of generic types is within the class, but is visible to anything that can see the class definiton I believe –  Aug 21 '14 at 10:55
  • No even if Box is next to fruit, it cannot see fruit's type t. – nmore Aug 21 '14 at 18:14
0

Solution Edited:

interface Fruit<T> {
    T get();
}

class Box<F extends Fruit<?>> {

    <R> R get(F fruit) { 
        @SuppressWarnings("unchecked")
        R ret = (R) fruit.get();

        return ret;
    }
}

class Apple implements Fruit<String> {
    @Override
    public String get() {
        return "Apple";
    }
}

class Something implements Fruit<String> {
    @Override
    public String get() {
        return "Something";
    }
}

//this is what I would like, but this won't compile with above definiton
class AppleBox extends Box<Apple> {
    // ...
}

class Main {
    public static void main(String[] argv) {

        Apple apple = new Apple();
        Something something = new Something();

        AppleBox ab = new AppleBox();

        System.out.println( ab.get(apple) );
        // this will fail
        System.out.println( ab.get(something) );)
    }
}

And if you want more type safeness about the Box.get() return type, just use static method because the above Box.get() returns Object, not T.

interface Fruit<T> {
    T get();
}

class Box<F extends Fruit<?>> {

    <R> R get(F fruit) { 
        @SuppressWarnings("unchecked")
        R ret = (R) fruit.get();
        return ret;
    }

    public static <P, Q extends Fruit<P>> P get(Box<Q> box, Q fruit) {
        return box.get(fruit);
    }
}

class Apple implements Fruit<String> {
    @Override
    public String get() {
        return "Apple";
    }
}

class Something implements Fruit<String> {
    @Override
    public String get() {
        return "Something";
    }
}

//this is what I would like, but this won't compile with above definiton
class AppleBox extends Box<Apple> {
    // ...
}

class Main {
    public static void main(String[] argv) {

        Apple apple = new Apple();
        Something something = new Something();

        AppleBox ab = new AppleBox();

        System.out.println( AppleBox.get(ab, apple) );      
        System.out.println( AppleBox.get(ab, something) );  // this will fail

        Apple p = AppleBox.get(ab, apple); // fail: return type mismatch
    }
}
Byungjoon Lee
  • 913
  • 6
  • 18
  • Not quite, I should have stiplulated that inspectEngine was abstract to imply that its something to be implemented in further classes and they should not have choice to implement returning an Engine type that does not match their Car type –  Aug 21 '14 at 10:53
  • I modified the answer as above. I think this will be the closest solution to your need. – Byungjoon Lee Aug 22 '14 at 03:54