Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a use case for a generic constructor?

Consider the following constructor for the class Foo (which for the sake of clarity is not a generic class):

public <T> Foo(T obj) { }

This is valid syntax for constructors, just like with normal generic methods.

But what is the use of this syntax? Typically generic methods provide type safety for their return type, and can benefit from type inference by the compiler. For example:

Pair<String, Integer> stringInt = Pair.of("asfd", 1234);

But a call to a constructor always returns an instance of its declaring class, so its type parameters have no effect on the return type. The constructor above could just be replaced with its erasure:

public Foo(Object obj) { }

Of course generics aren't only about type safety for return types. The constructor might just want to constrain the type of argument(s) being passed in. However, the above reasoning still applies for a bounded type parameter:

public <N extends Number> Foo(N number) { }

public Foo(Number number) { } //same thing

Even nested type parameters with bounds are handled using wildcards:

public <N extends Number, L extends List<N>> Foo(L numList) { }

public Foo(List<? extends Number> numList) { } //same thing

So what is a legitimate use case for having a generic constructor?

like image 694
Paul Bellora Avatar asked Feb 22 '12 23:02

Paul Bellora


4 Answers

Here's a possible one, adapted from functional programming. Suppose we have a Stream type that has some internal state, repeatedly yielding new elements until it returns null. The outside callers don't care what the internal state type of the stream type is, so you might get something like

class Stream<E> {
  <S> Stream(S initialState, StepFunction<E, S> stepFun) {
    ...
  }
}

without the recipient having to know what the internal state type is.

like image 89
Louis Wasserman Avatar answered Oct 23 '22 19:10

Louis Wasserman


One thing I can think off of the top of my head is that you can ensure that bounds are fulfilled in the same way across multiple parameters.

Take an obviously stupid and contrived but valid constructor that copies a list from a source to a target:

public <T> Foo (List<T> listA, List<T> listB) {
    listA.addAll(listB);
}

Using wildcards here would quickly become pretty nasty and probably not do what you want anyway. It would also be a totally arbitrary restriction to disallow it. So it makes sense to me that the language spec allows it.

like image 43
Steven Schlansker Avatar answered Oct 23 '22 21:10

Steven Schlansker


One use case that I can think of is when you want to constrain a constructor argument to more than one type. Only the generic syntax allows you to declare a constructor taking a List of Numbers that also implements RandomAccess:

public <L extends List<? extends Number> & RandomAccess> Foo(L raNumList) { }

...

Foo f1 = new Foo(new ArrayList<Integer>());
Foo f2 = new Foo(new LinkedList<Integer>()); //compiler error
like image 26
Paul Bellora Avatar answered Oct 23 '22 20:10

Paul Bellora


You can enforce certain constraints for the constructor parameters. E.g. the following code requires two parameters which implement the interfaces InterfaceA and InterfaceB.

<T extends InterfaceA & InterfaceB > Foo(T t1, T t2) {

}
like image 40
Thomas Avatar answered Oct 23 '22 19:10

Thomas