0

Could someone help me to fix this compilation error, please?

I 'd like to define a map method in the generic interface called Suite and use it like this:

Suite < Integer > suite2 = Suite.from("34", "78", "23").map(Integer::parseInt);

assertEquals(3, suite.size());
assertEquals(34, (int)suite.get(0));
assertEquals(78, (int)suite.get(1));
assertEquals(23, (int)suite.get(2));

The the call to the same method with a function and parameter compile well:

Suite<Integer> suite1 = Suite.from(1, 2).map(x -> x * 2);

assertEquals(2, suite.size());
assertEquals(2, (int)suite.get(0));
assertEquals(4, (int)suite.get(1));

So I've defined the method in the interface like this

public interface Suite<E> {

    public <E> Suite<E> map(int i, Function<? super E, ? extends E> f);
}

Note: this is almost the same protytype as the map method of Stream class (except the paramter i )

My problem is in my test, this line does not compile:

map(Integer::parseInt)

because of these errors:

  • The type Integer does not define toString(Object) that is applicable here.
  • Type mismatch: cannot convert Suite<Object> to Suite<String>

I'm tried to redefine the function with a Supplier<E> but it does not work.

Andrew Tobilko
  • 44,067
  • 12
  • 74
  • 128
Toto
  • 9
  • 4
  • Your code doesn't make sense. What kind of parameter do you expect to pass to the function? `E` or not `E`? – SLaks Jan 10 '18 at 20:36
  • just spitballing here, what if you used `.span(1, x -> x.toString())` – corsiKa Jan 10 '18 at 20:37
  • THis might be your problem. Function super E, ? extends E> – Jose Martinez Jan 10 '18 at 20:37
  • try to define 2 generic classes `public Suite map(int i, Function super E, ? extends F> ;` – radistao Jan 10 '18 at 21:19
  • Please see my updated post with all the use case test. – Toto Jan 10 '18 at 21:22
  • Radistao, your proposition does not work. This line does not compile anymore : Suite suite = Suite.from(1, 2).map(x -> x * 2) whereas it compiled with my version. Thanks anyway ! – Toto Jan 10 '18 at 21:31
  • corsiKa, it works if I change the call like you have proposed. But I cannot change it which is the specification how the class Suite could be used. – Toto Jan 10 '18 at 21:35
  • well, it is completely mess now: `Suite map(int i, Function super E, ? extends E> f)` accepts 2 arguments (Integer and Function, but `map(Integer::parseInt)` passes only Function, missing Integer. Isn't it? – radistao Jan 10 '18 at 21:40
  • Radisto, you are right. Thank you! There is no problem with the map method. This non-static map compiles well. My problem was the static function span. I 'll try to see why static method makes the program test not compiled. – Toto Jan 10 '18 at 22:50
  • Finally, it seems that the problem is due to the test which is not compatible with new java version : calling Integer::toString is not valid anymore and now, it is recommanded to use Objects::toString .... Thank you all for your help ! – Toto Jan 10 '18 at 23:09
  • You have two unrelated type parameters with the same name `` in your interface. That’s *not*, how `Stream.map` works… – Holger Jan 11 '18 at 08:14

2 Answers2

2
 Function<? super E, ? extends E> function

Integer is not a super class of String, hence this fails:

Suite <String> suite1 = Suite.span(1, Integer::toString);

reference: Difference between <? super T> and <? extends T> in Java

Jose Martinez
  • 9,918
  • 6
  • 41
  • 60
  • In fact, this method must be able used in the same way the map of the Stream class. (Please my post updated). And I used the same prototype. The test case is the specification so I think it must work – Toto Jan 10 '18 at 21:20
  • 1
    @Toto Your is not at all the same. `Stream.map()` has two generic types: `T` (the input type, defined at the class level) and `R` (the return type). – shmosel Jan 10 '18 at 21:28
2

Usually functional mapping expects type changing, e.g. argument and result types are diverged:

https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#map-java.util.function.Function-

Suite < Integer > suite2 = Suite.from("34", "78", "23").map(Integer::parseInt);

Here you change String type to Integer, thus you can't use common E generic name like

public <E> Suite<E> map(int i, Function<? super E, ? extends E> f);

but:

public <T, R> Suite<R> map(int i, Function<? super T, ? extends R> f);

or:

public interface Suite<E> {
    public <R> Suite<R> map(int i, Function<? super E, ? extends R> f);
}
radistao
  • 12,489
  • 8
  • 51
  • 80
  • radistao, juste tried your idea . So I added the second type R : public Suite map(int i, Function super E, ? extends R> f); but many lines won't compile. Example: Suite.from("abc", "def", "ghi") .map(String::length) – Toto Jan 10 '18 at 21:47
  • Radistao, other error: this line does not compile any more, after adding a return type R in the prototype : Suite suite = Suite.from(1, 2).map(x -> x * 2); – Toto Jan 10 '18 at 21:49
  • could you show whole `Suite` class? It is not clear what exactly should be done – radistao Jan 10 '18 at 21:49
  • as i mentioned in another commend above: you methods arguments list are mismatched – radistao Jan 10 '18 at 21:50
  • public interface Suite { @SafeVarargs public static Suite from(E... values) { return new SuiteImpls<>(values); } public Suite map(int i, Function super E, ? extends R> fun); } – Toto Jan 10 '18 at 22:04
  • The interface is almost empty. I'am trying to get an interface working with the test program. – Toto Jan 10 '18 at 22:07
  • 1
    remove `int i, ` from map function – radistao Jan 10 '18 at 23:16