<Out T> VS <T> in Generics

out T vs T in Generics

The out keyword in generics is used to denote that the type T in the interface is covariant. See Covariance and contravariance for details.

The classic example is IEnumerable<out T>. Since IEnumerable<out T> is covariant, you're allowed to do the following:

IEnumerable<string> strings = new List<string>();
IEnumerable<object> objects = strings;

The second line above would fail if this wasn't covariant, even though logically it should work, since string derives from object. Before variance in generic interfaces was added to C# and VB.NET (in .NET 4 with VS 2010), this was a compile time error.

After .NET 4, IEnumerable<T> was marked covariant, and became IEnumerable<out T>. Since IEnumerable<out T> only uses the elements within it, and never adds/changes them, it's safe for it to treat an enumerable collection of strings as an enumerable collection of objects, which means it's covariant.

This wouldn't work with a type like IList<T>, since IList<T> has an Add method. Suppose this would be allowed:

IList<string> strings = new List<string>();
IList<object> objects = strings; // NOTE: Fails at compile time

You could then call:

objects.Add(new Image()); // This should work, since IList<object> should let us add **any** object

This would, of course, fail - so IList<T> can't be marked covariant.

There is also, btw, an option for in - which is used by things like comparison interfaces. IComparer<in T>, for example, works the opposite way. You can use a concrete IComparer<Foo> directly as an IComparer<Bar> if Bar is a subclass of Foo, because the IComparer<in T> interface is contravariant.

what is in T and out T in Generics

<out T> denotes that T is covariant.

It seems plausible that a sequence of giraffes can be treated as a sequence of animals. "Covariance" of an interface means that "if there is an implicit reference conversion from Giraffe to Animal then there is also an implicit reference conversion from I<Giraffe> to I<Animal>. The convertibility of the constructed type "varies in the same direction" as the convertibility of the type arguments.

Example:

// Valid!                                // Invalid!
// Every giraffe is an animal // Not every animal is a giraffe
IEnumerable<Giraffe> giraffes = ...; IEnumerable<Animal> animals = ...;
IEnumerable<Animal> animals = giraffe; IEnumerable<Giraffe> giraffes = animals;
Animal animal = animals.First(); Giraffe giraffe = giraffes.First();

<in T> denotes that T is contravariant.

It seems plausible that code which can compare two animals can also compare two giraffes. "Contravariance" of an interface is the same as covariance with the direction reversed. It means that "if there is an implicit reference conversion from Giraffe to Animal then there is also an implicit reference conversion from I<Animal> to I<Giraffe>. The convertibility of the constructed type "varies in the opposite direction" as the convertibility of the type arguments.

Example:

// Valid!                                // Invalid!
// Animal comparer can compare // Giraffe comparer cannot compare
// giraffes // arbitrary animals
IComparer<Animal> animalC = ...; IComparer<Giraffe> giraffeC = ...;
IComparer<Giraffe> giraffeC = animalC; IComparer<Animal> animalC = giraffeC;
int result = giraffeC.Compare(x, y); int result = animalC.Compare(x, y);

See:

  • Covariance and Contravariance (C# and Visual Basic)
  • Variance in Generic Interfaces (C# and Visual Basic)
  • out (Generic Modifier) (C# Reference)
  • in (Generic Modifier) (C# Reference)

Is it possible to use the generic in and out modifier on the same T?

One could have interfaces IReadable<out T> { T read(int index); }, IWritable<in T> { void write(int index, T dat);, ISplitReadWrite<out Tout, in Tin>:IReadable<Tout>,IWritable<Tin>, and IReadWrite<T>:ISplitReadWrite<T,T>.

If one has a class MyCollection<T> which implements IReadWrite<T>, then a MyCollection<Cat> could be converted to IReadable<Animal>, IWritable<SiameseCat>, or an ISplitReadWrite<Animal,SiameseCat>. Note, however, that the only IReadable<T> that would yield an item that could be stored into a MyCollection<Cat> would be IReadable<Cat>, the only IWritable<T> that could handle everything that might appear in a MyCollection<Cat> would be IWritable<Cat>. The only forms of ISplitReadWrite<Tout,Tin> that would allow one to read out an item and write it back to the same collection without a cast would be those where the two types were the same, and the only such type implemented by MyCollection<Cat> would be ISplitReadWrite<Cat,Cat>.

Note that one could have an interface with methods that could be equally usable with MyCollection<Animal> and MyCollection<SiameseCat>, such as "swap the items in slots i1 and i2 of the same collection", but such an interface wouldn't need any generic parameter at all. Id one has an IPermutable interface, it could include methods like void swapItems(int i1, int i2); which wouldn't have any generic types in their signatures, and thus wouldn't make it necessary for the type to include any generic type arguments.

What does out mean before a Generic type parameter?

It is one of the two generic modifiers introduces in C# 4.0 (Visual Studio 2010).

It signifies that the generic parameter it is declared on is covariant.

The in modifier signifies the generic parameter it is declared on is contravariant.

See out (Generic Modifier) and in (Generic Modifier) on MSDN.

Typescript generic type parameters: T vs T extends {}

Note: I'll assume you're using a version of TypeScript 3.5 or later; in TypeScript 3.5 a change was made so that generic type parameters are implicitly constrained by unknown instead of the empty object type {}, and some minor details about the difference between funcA() and funcB() changed. I don't want to make a long post even longer by talking about how things used to be in TS3.4 and below.


If you don't explicitly constrain a generic type parameter via extends XXX, then it will implicitly be constrained by unknown, the "top type" to which all types are assignable. So in practice that means the T in funcA<T>() could be absolutely any type you want.

On the other hand, the empty object type {}, is a type to which nearly all types are assignable, except for null and undefined, when you have enabled the --strictNullChecks compiler option (which you should). Even primitive types like string and number are assignable to {}.

So compare:

function funcA<T>() { }
funcA<undefined>(); // okay
funcA<null>(); // okay
funcA<string>(); // okay
funcA<{ a: string }>(); // okay

with

function funcB<T extends {}>() { }
funcB<undefined>(); // error
funcB<null>(); // error
funcB<string>(); // okay
funcB<{ a: string }>(); // okay

The only difference is that T extends {} forbids null and undefined.


It might be a little confusing that {}, a so-called "object" type, would accept primitives like string and number. It helps to think of such curly-brace-surrounded types like {} and {a: string} as well as all interface types not necessarily as "true" object types, but as types of values where you can index into them as if they were objects without getting runtime errors. Primitives except for null and undefined are "object-like" in that you can treat them as if they were wrapped with their object equivalents:

const s: string = "";
s.toUpperCase(); // okay

And therefore even primitives like string are assignable to curly-brace-surrounded types as long as the members of those types match:

const x: { length: number } = s; // okay

If you really need to express a type that only accepts "true", i.e., non-primitive objects, you can use the object:

const y: object & { length: number } = s; // error
const z: object & { length: number } = { length: 10 }; // okay

But I (seriously) digress.


Okay, hope that helps; good luck!

Playground link to code

What is the difference between 'E', 'T', and '?' for Java generics?

Well there's no difference between the first two - they're just using different names for the type parameter (E or T).

The third isn't a valid declaration - ? is used as a wildcard which is used when providing a type argument, e.g. List<?> foo = ... means that foo refers to a list of some type, but we don't know what.

All of this is generics, which is a pretty huge topic. You may wish to learn about it through the following resources, although there are more available of course:

  • Java Tutorial on Generics
  • Language guide to generics
  • Generics in the Java programming language
  • Angelika Langer's Java Generics FAQ (massive and comprehensive; more for reference though)

Java Generics WildCard: ? extends Number vs T extends Number

There is no difference in this case, because T is never used again.

The reason for declaring a T is so that you can refer to it again, thus binding two parameter types, or a return type together.

What is out keyword in kotlin

With this signature:

List<out T>

you can do this:

val doubleList: List<Double> = listOf(1.0, 2.0)
val numberList: List<Number> = doubleList

which means T is covariant:

when a type parameter T of a class C is declared out, C<Base> can safely be a supertype of C<Derived>.

This is contrast with in, e.g.

Comparable<in T>

you can do this:

fun foo(numberComparable: Comparable<Number>) {
val doubleComparable: Comparable<Double> = numberComparable
// ...
}

which means T is contravariant:

when a type parameter T of a class C is declared in, C<Derived> can safely be a supertype of C<Base>.

Another way to remember it:

Consumer in, Producer out.

see Kotlin Generics Variance

-----------------updated on 4 Jan 2019-----------------

For the "Consumer in, Producer out", we only read from Producer - call method to get result of type T; and only write to Consumer - call method by passing in parameter of type T.

In the example for List<out T>, it is obvious that we can do this:

val n1: Number = numberList[0]
val n2: Number = doubleList[0]

So it is safe to provide List<Double> when List<Number> is expected, hence List<Number> is super type of List<Double>, but not vice versa.

In the example for Comparable<in T>:

val double: Double = 1.0
doubleComparable.compareTo(double)
numberComparable.compareTo(double)

So it is safe to provide Comparable<Number> when Comparable<Double> is expected, hence Comparable<Double> is super type of Comparable<Number>, but not vice versa.

Difference between ? super T and ? extends T in Java

extends

The wildcard declaration of List<? extends Number> foo3 means that any of these are legal assignments:

List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>(); // Double extends Number
  1. Reading - Given the above possible assignments, what type of object are you guaranteed to read from List foo3:

    • You can read a Number because any of the lists that could be assigned to foo3 contain a Number or a subclass of Number.
    • You can't read an Integer because foo3 could be pointing at a List<Double>.
    • You can't read a Double because foo3 could be pointing at a List<Integer>.
  2. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments:

    • You can't add an Integer because foo3 could be pointing at a List<Double>.
    • You can't add a Double because foo3 could be pointing at a List<Integer>.
    • You can't add a Number because foo3 could be pointing at a List<Integer>.

You can't add any object to List<? extends T> because you can't guarantee what kind of List it is really pointing to, so you can't guarantee that the object is allowed in that List. The only "guarantee" is that you can only read from it and you'll get a T or subclass of T.

super

Now consider List <? super T>.

The wildcard declaration of List<? super Integer> foo3 means that any of these are legal assignments:

List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>(); // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>(); // Object is a superclass of Integer
  1. Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from List foo3:

    • You aren't guaranteed an Integer because foo3 could be pointing at a List<Number> or List<Object>.
    • You aren't guaranteed a Number because foo3 could be pointing at a List<Object>.
    • The only guarantee is that you will get an instance of an Object or subclass of Object (but you don't know what subclass).
  2. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments:

    • You can add an Integer because an Integer is allowed in any of above lists.
    • You can add an instance of a subclass of Integer because an instance of a subclass of Integer is allowed in any of the above lists.
    • You can't add a Double because foo3 could be pointing at an ArrayList<Integer>.
    • You can't add a Number because foo3 could be pointing at an ArrayList<Integer>.
    • You can't add an Object because foo3 could be pointing at an ArrayList<Integer>.

PECS

Remember PECS: "Producer Extends, Consumer Super".

  • "Producer Extends" - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T, e.g. List<? extends Integer>. But you cannot add to this list.

  • "Consumer Super" - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T, e.g. List<? super Integer>. But there are no guarantees what type of object you may read from this list.

  • If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List<Integer>.

Example

Note this example from the Java Generics FAQ. Note how the source list src (the producing list) uses extends, and the destination list dest (the consuming list) uses super:

public class Collections { 
public static <T> void copy(List<? super T> dest, List<? extends T> src) {
for (int i = 0; i < src.size(); i++)
dest.set(i, src.get(i));
}
}

Also see
How can I add to List<? extends Number> data structures?



Related Topics



Leave a reply



Submit