7

Consider the UnaryFunction interface defined in Effective Java generics chapter .

public interface UnaryFunction<T> {
T apply(T arg);
}

and the following code for returning the UnaryFunction

// Generic singleton factory pattern
private static UnaryFunction<Object> IDENTITY_FUNCTION = new UnaryFunction<Object>() {
  public Object apply(Object arg) { return arg; }
};

// IDENTITY_FUNCTION is stateless and its type parameter is
// unbounded so it's safe to share one instance across all types.
@SuppressWarnings("unchecked")
public static <T> UnaryFunction<T> identityFunction() {
  return (UnaryFunction<T>) IDENTITY_FUNCTION;
}

Why is the cast of IDENTITY_FUNCTION to (UnaryFunction<T>) safe ?

The book says this about the question I am asking but I can't follow the logic here . Where are we invoking the apply function which does the identity operation ? i am confused because it is that function which returns the same object passed into it without modifying anything .

The cast of IDENTITY_FUNCTION to (UnaryFunction<T>) generates an unchecked cast warning, as UnaryFunction<Object> is not a UnaryFunction<T> for every T. But the identity function is special: it returns its argument unmodified, so we know that it is typesafe to use it as a UnaryFunction<T> whatever the value of T. Therefore, we can confidently suppress the unchecked cast warning that is generated by this cast. Once we’ve done this, the code compiles without error or warning.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
Geek
  • 26,489
  • 43
  • 149
  • 227
  • Side question: what book are you using, and does it say what the point of this code is? – asteri Feb 25 '13 at 17:00
  • @Jeff Effective java is the book name and it is there in generics chapter , specifically in the section that describes generic functions. – Geek Feb 25 '13 at 17:11

3 Answers3

3

With type erasure

T apply(T arg);

actually is

Object apply(Object arg);

Now for identity

Abc x = ...;
Abc y = IDENTITY.apply(x);

one may assume that it always is correct (is equivalent to y = x;).

(Very pragmatic.)

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Whenever identityFunction is applied (.apply) the result is assigned T IDENTITY.apply(T), which normally cannot be done, as the parameter's T is not there at runtime. – Joop Eggen Feb 25 '13 at 17:44
3

The cast is safe insomuch only as the identity function returns the exact object that was passed to it in the first place. As such, at runtime, there is no specialization of the generic parameter T that can violate the cast.

Aka, you are casting an object as it's own type.

Perception
  • 79,279
  • 19
  • 185
  • 195
1

identityFunction() simply returns the function itself, to be used on different objects.

Following is a usage example:

String result = identityFunction().apply("Hello");

The type safety warning is important. It's there because IDENTITY_FUNCTION is implemented such that the compiler can't guarantee that the function returns the same type as the input. Consider the following alternative implementation:

private static UnaryFunction<Object> CONST_FUNCTION = new UnaryFunction<Object>() {
    public Object apply(Object arg) { return "Default"; } 
};

This implementation always returns a string, so it's obviously not safe to return it as a unary function on a generic data type.

In our case (IDENTITY_FUNCTION), the proof that the returned type is the same as the input type is inside the implementation. We return the same instance, so it's guaranteed to have the same type. When you suppress type safety warnings, it's recommended to justify it with a proof.

Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78
  • -1 Confusing. IdentityFunction() does not return the "function itself", it returns the _argument_ itself. I see no reason why this result, of type T is "to be used on different objects". In your example, it is a String which _cannot_ be _used_ on different objects. – user949300 Feb 25 '13 at 17:41
  • 1
    @user949300: `identityFunction()` returns a reference to the object stored in the variable `IDENTITY_FUNCTION`. That reference allows you to call `apply()`, thus `identityFunction()` effectively returns the function itself. It would have been better if the names were not the same. Ex `getIdentityFunction()` and `IDENTITY_FUNCTION`. The first line of the answer is referring to the getter method. – unholysampler Feb 25 '13 at 17:53
  • thanks - understood. This whole question/system is very confusing for something that does nothing :-). I can't "undo" my downvote though until you edit your answer due to limitations in StackOverflow. – user949300 Feb 25 '13 at 18:49