0

Mapping function is pretty much a copy of standard mapping function:

public <R> ObjStack<R> map(Function<T, R> mapping) {
    return ObjStack.of(mapping.apply((T) current), history());
}

Where T is inherited from class signature ObjStack<T>

Using

Function<Object, Integer> f = x -> x.hashCode();

as argument fails.

Object is definitely in scope of T and Integer shouldn't matter as it's R which isn't constrained.

 someInstance.map(x -> x + 1)

also errors, someInstance is of type ObjStack<Number>. Data is referenced using type Object internally. I'm using and limited to Java 8.

Edit:

Error codes:

Error: line (7)
java: method map in class ObjStack<T> cannot be applied to given types;
  required: java.util.function.Function<java.lang.Number,R>
  found: java.util.function.Function<java.lang.Object,java.lang.Integer>
  reason: cannot infer type-variable(s) R
    (argument mismatch; java.util.function.Function<java.lang.Object,java.lang.Integer> cannot be converted to java.util.function.Function<java.lang.Number,R>)
Error: line (9)
java: bad operand types for binary operator '+'
  first type:  java.lang.Number
  second type: int
Tin Svagelj
  • 124
  • 1
  • 13
  • Try `public R map(Function super T, ? extends R> mapping) { ... }`. – Slaw Oct 09 '19 at 17:54
  • `x -> x.hashCode()` shouldn't really fail for a `Function`, could you complete the code with the error that you're getting? On another note `Number` doesn't support `+` operator. See [this](https://stackoverflow.com/questions/2721390/how-to-add-two-java-lang-numbers) for details. – Naman Oct 09 '19 at 18:03

1 Answers1

1

In order to provide flexibility regarding the generic signature of the actual Function argument you need to specify the appropriate upper and lower bounds for the parameter type:

public <R> R map(Function<? super T, ? extends R> mapping) {
    // code
}

Without those bounds the Function implementation would have to match T and R exactly. With those bounds the Function implementation can match T or use any supertype of T and match R or use any subtype of R. The reason the first generic parameter uses super and the second generic parameter uses extends is because the Function consumes an object of type T and produces an object of type R—see What is PECS (Producer Extends Consumer Super)?.


Regarding:

someInstance.map(x -> x + 1)

If someInstance is a ObjStack<Number> then x is a Number in that Function. In other words, you've created a Function<Number, ???> (where I put ??? because I don't know if the return type is supposed to be Number or, for instance, Integer). In Java, objects of type Number cannot be used with mathamatical operators (i.e. +). You'll need to convert x to an appropriate type, for instance:

someInstance.map(x -> x.intValue() + 1);
Slaw
  • 37,820
  • 8
  • 53
  • 80
  • `x -> x.hashCode()` should work with OP's signature as well. – Naman Oct 09 '19 at 18:16
  • Yes, but `Function f = x -> x.hashCode()` would not work with the OP's current signature; they wouldn't be able to pass `f` directly without the `? super T` bounds. – Slaw Oct 09 '19 at 18:17
  • Depends really how its initialised. This `ObjStack someInstance = new ObjStack<>(); someInstance.map(x -> x.hashCode());` would work still. – Naman Oct 09 '19 at 18:24
  • Yes, that would work. But the OP appears to be using something akin to `Function f = x -> x.hashCode(); ObjStack someInstance = new ObjStack<>(); someInstance.map(f);`. As a matter of course one should default to using upper/lower bounded wildcards anyway, unless there's a good reason not to. – Slaw Oct 09 '19 at 18:31