Search code examples
c#genericsvargeneric-type-argument

Why compiler does not allow us to use `var` instead of `generic type`?


In the example code below Generic Type is used in writing a Reverse function that reverses an array of any type:

public T[] Reverse<T>(T[] array)
{
    var result = new T[array.Length];
    int j=0;
    for(int i=array.Length; i>= 0; i--)
    {
        result[j] = array[i];
        j++;
    }
    return result;
}

However, I could write the same code like below by using var type:

public var[] Reverse(var[] array)
{
    var result = new var[array.Length];
    int j=0;
    for(int i=array.Length; i>= 0; i--)
    {
        result[j] = array[i];
        j++;
    }
    return result;
}

However, the compiler does not accept the latter. I want know to the difference between Generic type and var?


Solution

  • It doesn't compile, so it doesn't work.

    The use of generics and the var are very different. var means "compiler, I'm lazy, please discover for me the single exact type that I should use here, inferring it from what I'm writing after the =" (there are some cases where it is mandatory to use var instead of writing explicitly the variable type, but we will ignore them) ... So for example

    var foo = "Hello";
    

    The foo variable type is string, because the compiler can infer it by looking at the type of the expression after the assignment =. The var is totally replaced by the "correct" type in the compiled program.

    So it would be equivalent to writing:

    string foo = "Hello";
    

    Generics instead are a way to make a method/class able to adapt to different types that are used in calling/creating them. In this instance the caller could

    int[] foo1 = Reverse(new int[] { 1, 2, 3, 4, 5);
    

    or

    long[] bar1 = Reverse(new long[] { 1, 2, 3, 4, 5);
    

    The compiler (because generics are resolved at compile time) will infer the type T (int or long) from the parameters used and will write it somewhere (in the compiled file). The runtime then will see this and create two different specialized versions of Reverse (one for int and one for long). But in this case T is an "openness" to the various possible types of parameters. In the case of var, there is a single possible type that the variable can be. So in the compiled file there is a Reverse<T> compiled method, while at runtime there are a Reverse<int> version of the method and a Reverse<long> version of the method (and if necessary the runtime will create other versions of the method).

    Using var as a parameter wouldn't have any meaning, and it would be a poorer syntax than the generics one, where the list of used generics are put somewhere (between the method name and the ( in this case) and you can have multiple generic types, like

    public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
    

    (that is the LINQ Select) where there are two generic parameters TSource and TResult. With your syntax you wouldn't be able to differentiate between the two generic parameters (there is a single var keyword), and you couldn't use var as is currently used (compiler, I'm lazy, please discover for the the type of this local variable).