Attempt #3: Cannot form expression of required type with two question marks in Java

98 Views Asked by At

My previous SSCCE was incorrect itself. I tried to write one more, but it was incorrect too. So, for now I don't understand the problem and hence can't write pure Java example and therefore am posting example with library classes:

import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;

public class DoubleQuestionMark3 {

   public static class MyClass {
   }

   public static void main(String[] args) {

      TableColumn<MyClass, ?> column = new TableColumn();

      Callback<TableColumn<MyClass, ?>, TableCell<MyClass, ?>> callback = new Callback<TableColumn<MyClass, ?>, TableCell<MyClass, ?>>() {
         @Override
         public TableCell<MyClass, ?> call(TableColumn<MyClass, ?> param) {
            return null;
         }
      };

      column.setCellFactory(callback);

   }
}

The question is same: how to prepare callback of appropriate class?

If it is impossible, then, firstly, please state it is really impossible and secondly, please, explain WHY it is impossible.

UPDATE

Specifying Object for callback doesn't help:

 Callback<TableColumn<MyClass, Object>, TableCell<MyClass, Object>> callback = new Callback<TableColumn<MyClass, Object>, TableCell<MyClass, Object>>() {
         @Override
         public TableCell<MyClass, Object> call(TableColumn<MyClass, Object> param) {
            return null;
         }
      };
1

There are 1 best solutions below

7
On

When you declare a variable with a type TableColumn<MyClass, ?>, the ? denotes an unknown type, so it is impossible to define an appropriately typed Callback variable, because it refers to an unknown type.

If you have generic code that can deal with an arbitrary type, you have to write that code in a class or method having a type variable, giving the unknown type a name, e.g., you can use a method reference:

public class DoubleQuestionMark3 {

    public static void main(String[] args) {
        TableColumn<MyClass, ?> column = new TableColumn();
        column.setCellFactory(DoubleQuestionMark3::call);
    }
    static <T> TableCell<MyClass, T> call(TableColumn<MyClass, T> param) {
        // fill with life...
        return new TableCell<>();
    }
}

This works, as code, working with an arbitrary type T, can be used, even if the caller doesn’t know the type, like with the TableColumn<MyClass, ?>.


Alternatively, you may move the entire initialization code into a generic method:

public class DoubleQuestionMark3 {

    public static void main(String[] args) {
        TableColumn<MyClass, ?> column = new TableColumn();
        initialize(column);
    }
    static <T> void initialize(TableColumn<MyClass, T> column) {
        Callback<TableColumn<MyClass, T>, TableCell<MyClass, T>> cellFactory
        = new Callback<TableColumn<MyClass, T>, TableCell<MyClass, T>>() {
            @Override
            public TableCell<MyClass, T> call(TableColumn<MyClass, T> param) {
                // fill with life
                return new TableCell<>();
            }
        };
        column.setCellFactory(cellFactory);
    }
}

Simply said, whenever you have an unknown type which appears at multiple places and you have to make sure, these occurrences of an unknown type refer to the same type, you need a named type variable.