Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't C# support implied generic types on class constructors?

Tags:

c#

.net

generics

C# doesn't require you to specify a generic type parameter if the compiler can infer it, for instance:

List<int> myInts = new List<int> {0,1,1,
    2,3,5,8,13,21,34,55,89,144,233,377,
    610,987,1597,2584,4181,6765};

//this statement is clunky
List<string> myStrings = myInts.
    Select<int,string>( i => i.ToString() ).
    ToList<string>();

//the type is inferred from the lambda expression
//the compiler knows that it's taking an int and 
//returning a string
List<string> myStrings = myInts.
    Select( i => i.ToString() ).
    ToList();

This is needed for anonymous types where you don't know what the type parameter would be (in intellisense it shows up as 'a) because it's added by the compiler.

Class-level type parameters don't let you do this:

//sample generic class
public class GenericDemo<T> 
{
    public GenericDemo ( T value ) 
    {
        GenericTypedProperty = value;
    }

    public T GenericTypedProperty {get; set;}
}

//why can't I do:
int anIntValue = 4181;
var item = new GenericDemo( anIntValue ); //type inference fails

//however I can create a wrapper like this:
public static GenericDemo<T> Create<T> ( T value )
{
    return new GenericDemo<T> ( value );
}

//then this works - type inference on the method compiles
var item = Create( anIntValue );

Why doesn't C# support this class level generic type inference?

like image 369
Keith Avatar asked Sep 05 '08 12:09

Keith


People also ask

Why there is no string in C?

There is no string type in C . You have to use char arrays. By the way your code will not work ,because the size of the array should allow for the whole array to fit in plus one additional zero terminating character.

Why C has no exception handling?

As such, C programming does not provide direct support for error handling but being a system programming language, it provides you access at lower level in the form of return values. Most of the C or even Unix function calls return -1 or NULL in case of any error and set an error code errno.

Why is C not outdated?

The C programming language doesn't seem to have an expiration date. It's closeness to the hardware, great portability and deterministic usage of resources makes it ideal for low level development for such things as operating system kernels and embedded software.

Why array bounds checking is not available in C?

This is due to the fact that C++ does not do bounds checking. Languages like Java and python have bounds checking so if you try to access an out of bounds element, they throw an error. C++ design principle was that it shouldn't be slower than the equivalent C code, and C doesn't do array bounds checking.


2 Answers

Why doesn't C# support this class level generic type inference?

Because they're generally ambiguous. By contrast, type inference is trivial for function calls (if all types appear in arguments). But in the case of constructor calls (glorified functions, for the sake of discussion), the compiler has to resolve multiple levels at the same time. One level is the class level and the other is the constructor arguments level. I believe solving this is algorithmically non-trivial. Intuitively, I'd say it's even NP-complete.

To illustrate an extreme case where resolution is impossible, imagine the following class and tell me what the compiler should do:

class Foo<T> {
    public Foo<U>(U x) { }
}

var x = new Foo(1);
like image 57
Konrad Rudolph Avatar answered Oct 01 '22 02:10

Konrad Rudolph


Thanks Konrad, that's a good response (+1), but just to expand on it.

Let's pretend that C# has an explicit constructor function:

//your example
var x = new Foo( 1 );

//becomes
var x = Foo.ctor( 1 );

//your problem is valid because this would be
var x = Foo<T>.ctor<int>( 1 );
//and T can't be inferred

You're quite right that the first constructor can't be inferred.

Now let's go back to the class

class Foo<T> 
{
    //<T> can't mean anything else in this context
    public Foo(T x) { }
}

//this would now throw an exception unless the
//typeparam matches the parameter
var x = Foo<int>.ctor( 1 );

//so why wouldn't this work?
var x = Foo.ctor( 1 );

Of course, if I add your constructor back in (with its alternate type) we have an ambiguous call - exactly as if a normal method overload couldn't be resolved.

like image 26
Keith Avatar answered Oct 01 '22 02:10

Keith