Lists with wildcards cause Generic voodoo error
(I assume here that Bar
and Baz
are both subtypes of Foo
.)
List<? extends Foo>
means a list of elements of some type, which is a subtype of Foo, but we don't know which type. Examples of such lists would be a ArrayList<Foo>
, a LinkedList<Bar>
and a ArrayList<Baz>
.
As we don't know which subtype is the type parameter, we can't put Foo
objects into it, neither Bar
or Baz
objects. But we still know that the type parameter is a subtype of Foo
, so every element already in the list (and which we can get from the list) must be a Foo
object, so we can use Foo f = list.get(0);
and similar things.
Such a list can only be used for taking elements out of the list, not to adding elements at all (apart from null
, but I don't know if the compiler actually allows this).
A List<Foo>
on the other hand allows adding any object which is a Foo
object - and as Bar
and Baz
are subtypes of Foo
, all Bar
and Baz
objects are Foo
objects, so they can be added, too.
F# compilation error: Unexpected type application
It looks that providing type parameters when treating method as a first class value isn't supported. I checked the F# specification and here are some important bits:
14.2.2 Item-Qualified Lookup
[If the application expression begins with:]
<types>
expr, then use<types>
as the type arguments andexpr
as the expression
argument.- expr, then use expr as the expression argument.
- otherwise use no expression argument or type arguments.
- If the [method] is labelled with the
RequiresExplicitTypeArguments
attribute then explicit type arguments must have
been given.
If you specify type arguments and arguments, then the first case applies, but as you can see, the specification requires some actual arguments too. I'm not quite sure what is the motivation behind this, though.
Anyway, if you use the type parameter anywhere in the type signature of the member, then you can specify it using type annotations like this:
type Foo() =
member this.Bar<´T> (arg0:string) : ´T =
Unchecked.defaultof<´T>
let f = new Foo()
"string" |> (f.Bar : _ -> Int32)
On the other hand, if you don't use the type parameter anywhere in the signature, then I'm not quite sure why you need it in the first place. If you need it just for some runtime processing, then you may be able to take the runtime type representation as an argument:
type Foo() =
member this.Bar (t:Type) (arg0:string) = ()
let f = new Foo()
"string" |> f.Bar typeof<Int32>
Collection? extends T vs CollectionT
Consider the following
class Animal { }
class Horse extends Animal { }
private static void specific(List<Animal> param) { }
private static void wildcard(List<? extends Animal> param) { }
Without the extends syntax you can only use the exact class in the signature
specific(new ArrayList<Horse>()); // <== compiler error
With the wildcard extends you can allow any subclasses of Animal
wildcard(new ArrayList<Horse>()); // <== OK
It's generally better to use the ? extends syntax as it makes your code more reusable and future-proof.
Storing different types of elements in a List in Java
Since the common ancestor of your classes is Object
, and because List<? extends Object>
does not make things any cleaner (after all, everything extends Object
) it looks like List<Object>
would be an OK choice.
However, such list would be a mixed bag: you would need to check run-time type of the object inside, and make decisions based on that. This is definitely not a good thing.
A better alternative would be creating your own class that implements operations on elements of the list the uniform way, and make one subclass for each subtype that implements these operations differently. This would let you treat the list in a uniform way, pushing the per-object differentiation into your wrappers.
public interface ItemWrapper {
int calculateSomething();
}
public abstract class IntWrapper implements ItemWrapper {
private int value;
public IntWrapper(int v) {
value=v;
}
public int calculateSomething() {
return value;
}
}
public abstract class DoubleListWrapper implements ItemWrapper {
private List<Double> list;
public DoubleListWrapper (List<Double> lst) {
list = lst;
}
public int calculateSomething() {
int res;
for (Double d : list) {
res += d;
}
return res;
}
}
// ...and so on
Now you can make a list of ItemWrapper
objects, and calculateSomething
on them without checking their type:
List<ItemWrapper> myList = new ArrayList<ItemWrapper>();
for (ItemWrapper w : myList) {
System.out.println(
w.calculateSomething());
}
Related Topics
When to Use a Constructor and When to Use Getinstance() Method (Static Factory Methods)
Does Java Have Any Mechanism for a Vm to Trace Method Calls on Itself, Without Using Javaagent, etc
Find Duplicate Element in Array in Time O(N)
Why Does Intellij Give Me "Package Doesn't Exist" Error
Java Threads and Number of Cores
Does Java Se 8 Have Pairs or Tuples
Use a .Jar Java Library API in C#
Add Multiple Items to an Already Initialized Arraylist in Java
Difference Between an Application Server and a Servlet Container
How Does Java Makes Use of Multiple Cores
How Does Java Object Casting Work Behind the Scene
Copying Text to the Clipboard Using Java
Remove Elements from a Hashset While Iterating
Why Were Most Java.Util.Date Methods Deprecated
Is There a Way in Java to Convert an Integer to Its Ordinal Name