-1

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;
         }
      };
Dims
  • 47,675
  • 117
  • 331
  • 600
  • Why aren't you just editing the existing questions you've written for this...? – Makoto Jun 06 '16 at 14:20
  • Because I got a literally correct answer from newbie. – Dims Jun 06 '16 at 14:20
  • 3
    Problem is the wildcard `?`. Why are you using one? `setCellFactory` requires a `Callback, TableCell>`as parameter, i.e. the same `S` and `T`. The wildcard doesn't fulfil that, it says it can be some "type". – Tunaki Jun 06 '16 at 14:23
  • @Tunaki I would like to have type-agnostic columns. But please don't worry with this. Now it is just Java question. – Dims Jun 06 '16 at 14:26
  • @Tunaki how to fulfill? Rewrite `callback` assignment statement to fullfill please – Dims Jun 06 '16 at 14:27
  • @Dims: forget about that assignment. As Tunaki already explained, the subsequent `setCellFactory` can’t be invoked on a `TableColumn`, regardless of how you initialize `callback`. – Holger Jun 06 '16 at 14:29
  • 1
    I think this will answer your question http://stackoverflow.com/questions/7360594/whats-the-difference-between-raw-types-unbounded-wild-cards-and-using-object-i – Tunaki Jun 06 '16 at 14:29
  • @Holger so, there are uninvokable methods in Java. How to write simplest one? – Dims Jun 06 '16 at 14:30
  • 1
    Possible duplicate of [Cannot form expression of type with two question marks in Java](http://stackoverflow.com/questions/37658938/cannot-form-expression-of-type-with-two-question-marks-in-java) – ManoDestra Jun 06 '16 at 14:30
  • @Dims It's unclear what you want to do, but you can make it compile by using `` instead of the wildcard `>`. – Tunaki Jun 06 '16 at 14:31
  • @Tunaki I tried `Object` but failed. How would you write with `Object`? – Dims Jun 06 '16 at 14:32
  • 1
    @Dims You need to understand the types involved. `TableColumn` is parameterized with 2 types, `S` and `T`. With `TableColumn`, you are saying that `S = MyClass` and `T = ` some unknown type. Now, you are trying to give a callback that expects `TableColumn, TableCell`, i.e. `TableColumn, TableCell`. _But_ you are giving it a `TableColumn, TableCell`, where `?` can refer to some _other_ unknown type. This cannot work since you need to ensure that the _three of them_ refer to same type. – Tunaki Jun 06 '16 at 14:35
  • @Tunaki how about `Object`? Is it known for you? If yes, then try an `Object` -- it won't work too. – Dims Jun 06 '16 at 14:37
  • @Dims Because look at your code. You still have `TableColumn`. – Tunaki Jun 06 '16 at 14:38
  • @Tunaki but look at your explanation. You said _But you are giving it a TableColumn, TableCell, where ? can refer to some other unknown type._ This is now wrong. Now I am passing `TableColumn, TableCell` where all classes are known. – Dims Jun 06 '16 at 14:40
  • @Dims And it ends with *This cannot work since you need to ensure that the three of them refer to same type.*. You can refer to http://stackoverflow.com/questions/7360594/whats-the-difference-between-raw-types-unbounded-wild-cards-and-using-object-i – Tunaki Jun 06 '16 at 14:41
  • `Object` IS "the same type", isn't it? – Dims Jun 06 '16 at 14:41
  • If you have a `TableColumn`, you can use a `Callback, TableCell>`. But since you have a `TableColumn`, you can’t use that callback, as you don’t know whether `?` stands for `Object`. – Holger Jun 06 '16 at 14:47

1 Answers1

1

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.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • So, what is the key reason for the problem? Why questionmarks work fine in other cases? In my other samples it was working even if occurred several times. What distinguishes this case from others? PS I know what question mark is. I just don't understand, why it doesn't work in some cases. – Dims Jun 06 '16 at 14:51
  • Since I don’t know what cases you are referring to and what is working there, I can’t tell you why they work. The method `setCellFactory` requires the `Callback` argument to be compatible with the `TableColumn`’s type and that’s simply not possible to verify with `?`. Well designed APIs will use `? extends …` and `? super …` types for such callbacks, allowing broader types, i.e. a callback consuming arbitrary `Object`s would be feasible, but we’re talking about JavaFX here… – Holger Jun 06 '16 at 14:57
  • 1
    Key reason: `setCellFactory(Callback, TableCell> value)` means that both types must use the *same* `T`, but `?` is not same as `?`, so when you create a `Callback, TableCell>` it won't work. `T` can be "unknown", but it has to be the *same* "unknown" , not two different unknowns. The `DoubleQuestionMark3.call()` method leaves `T` undefined, but the parameter and return value is guaranteed to be the same `T`, which is why that works. – Andreas Jun 06 '16 at 14:57
  • @Andreas The "sameness explanation" implies that code should work with `Object`, but it doesn't – Dims Jun 06 '16 at 15:01
  • @Andreas: actually, there are three occurrences to match, the two within the `Callback` signature and `TableColumn`’s own type parameter. – Holger Jun 06 '16 at 15:02
  • See for example [`List.sort(Comparator super E> c)`](https://docs.oracle.com/javase/8/docs/api/java/util/List.html#sort-java.util.Comparator-) and notice the `? super`. This allows comparators with a broader type than `E`, which implies, that a `List>` could be sorted with a `Comparator` as whatever actual element type the list has, a `Comparator` can handle that. This is different to `setCellFactory` which has no such relaxation in its signature. You need an exact match here. – Holger Jun 06 '16 at 15:07
  • @Dims Holger is correct, there are 3 '?' in your code. Two in the declaration of `callback` and one in the definition of `column`. All three *must* be the same, and `?` != `?` != `?`, but if you change *all three* to `Object`, it works. – Andreas Jun 06 '16 at 15:09