I'm working on an open-source Java library that will allow one to compute certain quantities, such as Gini index, of an attribute that takes on a finite number of values. (Formally, it computes the Gini index of the discrete distribution associated with the attribute A, but this is not relevant here.)
For example, one will be able to do the following
String[] namesArray = {"primary_school", "high_school", "university"};
Calculator<String> calc =new Calculator<String>(namesArray);
// p.getEducationLevel() returns `"primary_school"`, `"high_school"`, or `"university"`.
for (Person p : peopleCollection) {
calc.increment(p.getEducationLevel());
}
// e.g. the Gini index of the distribution
double currentStat = calc.getCurrentValue();
The idea is to allow users of the library to use their own type to refer to attribute values; in this case, I am using strings (e.g. "primary_school"). But I might want to use integers or even my own type AttributeValue.
I solve this by defining
public class Calculator<T> {
/* ... */
}
However, using generics causes some problems in the implementation: for example, if I want to maintain a collection of pairs of type (T, double), I have to do nasty type casts:
public class Calculator<T>
/* ... */
private Queue<StreamElement<T>> slidingWindow;
/* ... */
class StreamElement<T> {
private T label;
private double value;
StreamElement(T label, double value) {
this.label = label;
this.value = value;
}
public T getLabel() {
return label;
}
public double getValue() {
return value;
}
}
/* ... */
slidingWindow.add(new StreamElement<T>(label, value));
if (slidingWindow.size() > windowSize) {
StreamElement lastElement = slidingWindow.remove();
// XXX: Nasty type cast
decrement((T)lastElement.getLabel(), lastElement.getValue());
}
/* ... */
}
Here is the warning produced by javac:
Calculator.java:163: warning: [unchecked] unchecked cast
decrement((T)lastElement.getLabel(), lastElement.getValue());
^
required: T
found: Object
where T is a type-variable:
T extends Object declared in class Calculator
1 warning
Update. If I do not do the type cast, I get
Calculator.java:163: error: no suitable method found for decrement(Object,double)
decrement(lastElement.getLabel(), lastElement.getValue());
^
method Calculator.decrement(T) is not applicable
(actual and formal argument lists differ in length)
method Calculator.decrement(T,double) is not applicable
(actual argument Object cannot be converted to T by method invocation conversion)
where T is a type-variable:
T extends Object declared in class Calculator
1 error
Questions:
What is a proper, clean way to do the type cast?
What would be an alternative to using generics here?
More concretely, would it be better to instead define a class Label which user could extend to MyLabel and then use MyLabel for attribute values? This means that Calculator would no longer be a generic type; in the implementation we'd have class StreamElement { Label label; /* ... */ } et cetera.
I think you just made some mistake.
This is the correct implementation:
/* ... */
slidingWindow.add(new StreamElement<T>(label, value));
if (slidingWindow.size() > windowSize) {
// Don't forget the generic argument at StreamElement
StreamElement<T> lastElement = slidingWindow.remove();
decrement(lastElement.getLabel(), lastElement.getValue());
}
/* ... */
Related
I have two generic methods, which are designed to force the caller to provide parameters that match type wise:
private <T> void compareValues(Supplier<T> supplier, T value) {
System.out.println(supplier.get() == value);
}
private <T> void setValue(Consumer<T> consumer, T value) {
consumer.accept(value);
}
However, when calling them, the compiler reasons differently on what is allowed to pass as parameters:
compareValues(this::getString, "Foo"); // Valid, as expected
compareValues(this::getInt, "Foo"); // Valid, but compiler should raise error
compareValues(this::getString, 1); // Valid, but compiler should raise error
setValue(this::setString, "Foo"); // Valid, as expected
setValue(this::setInt, "Foo"); // Type mismatch, as expected
setValue(this::setString, 1); // Type mismatch, as expected
private String getString() {
return "Foo";
}
private int getInt() {
return 1;
}
private void setString(String string) {
}
private void setInt(int integer) {
}
How come? Is the compiler just too clumsy to properly reason about types here, or is this a feature of the type system? If so, what are the rules that lead to this behavior? Also, how would I create a "type safe" version of compareValues without adding artificial parameters, if at all possible?
Please note, that the provided methods merely contain a dummy implementation and do not reflect the code in my actual code base. The focus here are solely the method calls.
Others have mentioned why this is happening, so here's a solution to get around the problem.
If you create a generic class, separating the passing of the supplier from the passing of the argument, you do not give the compiler the opportunity to choose an intersection type:
public class Comparer<T>
{
private final Supplier<T> supplier;
Comparer(final Supplier<T> supplier)
{
this.supplier = supplier;
}
void compare(T value)
{
System.out.println(supplier.get() == value);
}
}
new Comparer<>(this::getString).compare("Foo"); // Valid, as expected
new Comparer<>(this::getInt).compare("Foo"); // Invalid, compiler error
new Comparer<>(this::getString).compare(1); // Invalid, compiler error
By separating out this behaviour, you also allow Comparer to do potentially useful things like caching the result of Supplier.get().
You can tell that the compiler choose an intersection type, by using
javac -XDverboseResolution=deferred-inference
output in one of the cases is:
instantiated signature: (Supplier<INT#1>,INT#1)void
target-type: <none>
where T is a type-variable:
T extends Object declared in method <T>compareValues(Supplier<T>,T)
where INT#1,INT#2 are intersection types:
INT#1 extends Object,Serializable,Comparable<? extends INT#2>
INT#2 extends Object,Serializable,Comparable<?>
Well here T can be anything. It is a synonym of a type but can be basically any type.
So when you have a compareValues(Supplier<T> supplier, T value) it means a supplier that can give me any type and value that can be of any type. So it doesn't give a compile error and it even works. In your method you can do:
private <T> void compareValues(Supplier<T> supplier, T value) {
value=supplier.get(); //It is still valid even if you give different types
System.out.println((supplier.get() == value) +" - "+ value);
}
As for the other method it is different because you say "Give me a consumer that accepts any type" but you give him a consumer that accepts just String.
So here
private void setString(String s) {
}
won't work but
private <T> void setString(T s) {
}
will work just fine.
It's like if you have a variable of type Object you can assign String to it but not the other way around in a more bizarre situation. A String supplier is a <T> supplier but a String consumer is not a <T> consumer.
See these two methods:
private <T> void setString(T a) {
T var=a;
T var2="Asdf"; //This doesn't compile! cannot convert String to T
}
private <String> void setString2(String a) {
String var=a;
String var2="asd";
}
You want consumer of type T which the first method is. But instead you try to give a consumer of type String which cannot work because it consumes just Strings and you want a method that can consume everything
As far as I know, using an upper bounded generic and using a superclass as a method parameter both accept the same possible arguments. Which is preferred, and what's the difference between the two, if any?
Upper bounded generic as parameter:
public <T extends Foo> void doSomething(T foo) {}
Superclass as parameter:
public void doSomething(Foo foo) {}
That's an upper bounded type parameter. Lower bounds are created using super, which you can't really do for a type parameter. You can't have a lower bounded type parameter.
And that would make a difference, if you, for example want to pass a List<T>. So, for the below two methods:
public <T extends Foo> void doSomething(List<T> foos) {}
public void doSomething(List<Foo> foo) {}
And for the given class:
class Bar extends Foo { }
The following method invocation:
List<Bar> list = new ArrayList<Bar>();
doSomething(list);
is valid for 1st method, but not for 2nd method. 2nd method fails because a List<Foo> is not a super type of List<Bar>, although Foo is super type of Bar. However, 1st method passes, because there the type parameter T will be inferred as Bar.
Generally, you only need a type variable when it's used in more than one place in class/method/field declarations. When you declare one on a method (rather than a class), the only places to use it are on the parameters and return value of that method.
For example, you can use it on multiple parameters to ensure their types match:
public static <T> void addToList(List<T> list, T element) {
list.add(element);
}
This is a trivial example, but you can see that it prevents you from giving it an element that doesn't match the list's generic type:
List<Integer> list = new ArrayList<>();
addToList(list, 7);
//addToList(list, 0.7); // doesn't compile
//addToList(list, "a"); // doesn't compile
You can also declare a parameter and the return type to be the same type:
public static <T> T nullCheck(T value, T defValue) {
return value != null ? value : defValue;
}
Since this method is returning one of the two T objects it's given, we can safely say that the returned object is also of type T.
Integer iN = null;
Integer i = nullCheck(iN, 7);
System.out.println(i); // "7"
Double dN = null;
Double d = nullCheck(dN, 0.7);
System.out.println(d); // "0.7"
Number n = nullCheck(i, d); // T = superclass of Integer and Double
System.out.println(n); // "7"
As for the example in the question, the type variable is only being used once, so it's equivalent to using the superclass. In this case you should avoid declaring a type variable, it's just unnecessary clutter.
Also I should note that the other answer changes the example to use List<T> and List<Foo>, but as mentioned in the comments, the superclass is really List<? extends Foo>, so no type variable is needed there, either.
I'm trying to make a generic class with one type parameter, class MyClass<E>, that has a class variable of a second generic class with two type parameters, SecondClass<V, E>. Since for my code it really doesn't matter what the type of V is, I declare the type of that variable as SecondClass<?, E> var. At some point in the implementation of MyClass I call a method on var that returns a V, public V foo(E e), and then I pass this object of type V to another method of var, public int bar(V v). However, this doesn't compile because of reasons I only vaguely understand, but I believe it is explained in here.
Apparently, the capture-of-? returned by foo is different from the the capture-of-? required by bar. But why? Whatever the actual type of V is, it must be the same for both methods, since they are invoked on the same instance. What am I missing here?
Ultimately, what I would like to know is this: what do I need to change in order to make the code compile, without adding V to the type parameters of MyClass? (I don't want to enforce users of MyClass to specify the type of V since it shouldn't matter)
To give you a more concrete example, here's a simplified version of what I'm working on. As you may already have guessed by the type parameters, it concerns graphs. MyClass translates to EdgePainter and SecondClass translates to Graph. With this code, the compile error is in the first line of EdgePainter.getColor(E).
class Graph<V, E>
{
public V getTarget(E edge)
{
return null;
}
public int getInDegree(V vertex)
{
return 0;
}
}
class EdgePainter<E>
{
private static final Color COLOR_FOR_MANY_EDGES = Color.RED;
private static final Color COLOR_FOR_FEW_EDGES = Color.BLUE;
private Graph<?, E> graph;
public EdgePainter(Graph<?, E> aGraph)
{
graph = aGraph;
}
public Color getColor(E edge)
{
// My compiler says:
// The method getInDegree(capture#3-of ?) in the type
// Graph<capture#3-of ?,E> is not applicable for the arguments
// (capture#4-of ?)
int degree = graph.getInDegree(graph.getTarget(edge));
if (degree > 10)
return COLOR_FOR_MANY_EDGES;
else
return COLOR_FOR_FEW_EDGES;
}
}
You can capture the wildcard by invoking a generic method.
public Color getColor(E edge) {
return getColorInternal(graph, edge);
}
private <X> Color getColorInternal(Graph<X, E> g, E e) {
int degree = g.getInDegree(g.getTarget(e));
// ...
}
This is a typical scenario. You need a type argument for the implementation, but want to hide it from API users. If many methods are affected it can be helpful to define a separate, perhaps nested, class EdgePainterInternal. This internal implementation has the second type parameter G and the publicly visible implementation EdgePainter delegates all calls to an instance of EdgePainterInternal.
This is a design similar to other JPA BaseEntity patterns you may have seen:
#MappedSuperclass()
public abstract class Entity<X extends Entity<X>>
implements
Comparable<X>,
Serializable
{
private static final long serialVersionUID = 1L;
private Long id;
private Date timeStamp;
...
// Simply compare fields in subclass until difference is discovered
private int compareSubclassFields(X that)
{
int result = 0;
for(Comparator<X> comparator : getComparators())
{
result = comparator.compare(this,that); <<=== compilation error
if(result != 0) { break; }
}
return result;
}
/**
* Entity subclasses provide a list of their own special
* comparators that can contribute to the comparison.
*/
protected abstract List<Comparator<X>> getComparators();
}
Here is an example of a class that extends Entity:
public class User extends Entity<User>
{
private static final long serialVersionUID = 1L;
private String firstName;
private String lastName;
private String email;
...
#Override
public List<Comparator<User>> getComparators()
{
List<Comparator<User>> result =
new ArrayList<Comparator<User>>();
result.add(getLastNameComparator()); // Sort first on last name
result.add(getFirstNameComparator());// Next, by first name
result.add(getEmailComparator()); // Finally, by email (unique)
return result;
}
}
When I compile, I get the following error:
error: method compare in interface Comparator<T> cannot be
applied to given types;
result = comparator.compare(this,that);
^
required: X,X
found: Entity<X>,X
reason: actual argument Entity<X> cannot be converted to
X by method invocation conversion
where X,T are type-variables:
X extends Entity<X> declared in class Entity
T extends Object declared in interface Comparator
Reading Java Enum Definition, in particular the part where it says,
public class StatusCode extends Enum<StatusCode>
Now if you check the constraints, we've got Enum - so E=StatusCode. Let's check: does E extend Enum? Yes! We're okay.
I assume that in my example, where X extends Entity<X>, 'this' would be an instance of User and not Entity<User>. Moreover, because Entity is an abstract class it must be extended and, therefore, compareNonIdFields can only be invoked by an instance of X -- on itself. Of course, when I cast I get the unchecked warning:
warning: [unchecked] unchecked cast
result = comparator.compare(((X)this),that);
^
required: X
found: Entity<X>
where X is a type-variable:
X extends Entity<X> declared in class Entity
1 warning
Thoughts on why this recursive generic usage causes a compilation error and solutions to make the unchecked cast warning go away would be greatly appreciated.
You are writing this keyword inside the Entity<X> class. So,
this = Entity<X>
On the other hand, you provided Comparator for X, not for Entity<X>.
You may keep a field to store related X object inside Entity<X> object and write in this manner:
result = comparator.compare(this.getX(),that);
Imagine the following two classes.
class Foo extends Entity<Bar> {}
class Bar extends Entity<Foo> {}
Clearly the comparison can not only be invoked on instances of X: If you invoke it on an instance of Foo then X = Bar and vice versa.
Edit: Just to be clear, while you intend to always substitute the inheriting type itself for X, this is not enforced by the language and/or the compiler. That's the source of your issue.
Weird! It's perfectly happy if you
result = comparator.compare((X)this, that);
So, are there any circumstances under which "this" might not be an X? Some odd permutation of subclassing and leaving the parameter unbound? Or further subclassing a subclass with a bound parameter?
A ha! It can happen if you subclass the class when X is already bound!
… no, that's not right. I gotta admit, I'm flummoxed.
I have a generic Callback object which provides a (primitive) callback capability for Java, in the absence of closures. The Callback object contains a Method, and returns the parameter and return types for the method via a couple of accessor methods that just delegate to the equivalent methods in Method.
I am trying to validate that a Callback I have been supplied points to a valid method. I need the return type assignment compatible with Number and all parameters to be assignment compatible with Double. My validating method looks like this:
static public void checkFunctionSpec(Callback cbk) {
Class[] prms=cbk.getParmTypes();
Class ret =cbk.getReturnType();
if(!Number.class.isAssignableFrom(ret)) {
throw new IllegalArgumentException(
"A function callback must return a Number type " +
"(any Number object or numeric primitive) - function '" +
cbk + "' is not permitted");
}
for(Class prm: prms) {
if(!Double.class.isAssignableFrom(prm)) {
throw new IllegalArgumentException(
"A function callback must take parameters of " +
"assignment compatible with double " +
"(a Double or Float object or a double or float primitive) " +
"- function '" + cbk + "' is not permitted");
}
}
}
The problem I encounter is that the when I try this with, e.g. Math.abs(), it's throwing an exception for the return type as follows:
java.lang.IllegalArgumentException:
A function callback must return a Number type (any Number object or numeric primitive)
- function 'public static double java.lang.Math.abs(double)' is not permitted
This was surprising to me because I expected primitives to simply work because (a) they are reflected using their wrapper classes, and (b) the Double.TYPE is declared to be of type Class<Double>.
Does anyone know how I can achieve this without modifying my checks to be:
if(!Number.class.isAssignableFrom(ret)
&& ret!=Double.TYPE
&& ret!=Float.TYPE
&& ret!=...) {
Clarification
When you invoke the method double abs(double) using Method.invoke(), you pass in a Object[]{Double} and get back a Double. However, my validation appears to be failing because Double.TYPE is not assignable to a Double. Since I require all these callbacks to return some sort of number, which will be returned by invoke() as a Number, I am trying to validate that the supplied method returns either Number or a numeric primitive.
Validation of the parms is likewise.
In other words, when using reflection the parm and return types Double and double are identical and I would like to validate them easily as such.
EDIT: To further clarify: I want to validate that a Method will, when invoke() is called return an Object of type Number (from which I can call obj.doubleValue() to get the double I want).
Looking more closely at the documentation for Class.isAssignableFrom(), it specifically states that the types for a primitive do not match any class except themselves. So I will need to specifically check for == equality to Byte.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, and Short.TYPE for the return type.
Why not have the compiler do it?
public interface F<A, B> {
public B $(A a);
}
Then you can pass an F<Double, Double> to a method that expects an F<? extends Number, ? extends Number>.
EDIT:
You say you want to provide a single class for the type of a function with any number of arguments. This can be done with the Java type system. Conceptually every function has only one argument. A function with two arguments is equivalent to a function that returns another function. So here's a variable whose value is a function that takes two doubles:
F<Double, F<Double, Double>> f;
Here's a method that passes two doubles to a given function:
public Double operate(F<Double, F<Double, Double>> f, double a, double b) {
return f.$(a).$(b);
}
Or, consider a type L<A extends L> with two subclasses C<E, T extends L<T>> representing a "cons", and a terminator type N:
public abstract class L<A extends L<A>> {
private L() {}
private static final N nil = new N();
public static N nil() {
return nil;
}
public static final class N extends L<N> {
private N() {}
public <E> C<E, N> cons(final E e) {
return new C<E, L>(e, this);
}
}
public static final class C<E, L extends L<L>> extends L<C<E, L>> {
private E e;
private L l;
private C(final E e, final L l) {
this.e = e;
this.l = l;
}
public E head() {
return e;
}
public L tail() {
return l;
}
public <E> C<E, C<E, L>> cons(final E e) {
return new C<E, C<E, L>>(e, this);
}
}
}
In such a case, you can implement a function type thusly:
public interface F<A extends L<A>, B> {
public B $(A args);
}
The following method expects a function with two Double arguments (and returns a Double), along with two doubles to apply it to:
public Double operate(F<C<Double, C<Double, N>>, Double> f, double a, double b) {
return f.$(N.nil().cons(b).cons(a));
}
The implementation of the F interface would have to get the arguments from the list using head and tail. So in effect, you're implementing LISP in Java. :)
Having said that, check out Functional Java, which is a library that has a lot of this stuff already. I'm sure there's also one out there that uses reflection so you don't have to write it yourself.
The parameter to Math.abs() is the double primitive. I'm not quite sure what you mean by a primitive being "assignment compatible" with an object (what the reflection API essentially means is "can be a cast of"). But if you mean "can pass into a Double constructor", then that's essentially a primitive double (or a string)!! Perhaps you need to clarify a bit more what you need to do?