Wednesday, 24 October 2012

Type System in C#


Type system in C#

In order to understand what the typing system in C# actually is we first need to define what we mean by statistically/dynamic typing, implicit/explicit typing and safe/unsafe typing. 
C# 1.0 is a statistically typed language; meaning that the type of any variable is known at compile time. There are also no implicit typing either. Meaning that the compiler doesn't have to derive the type of an expression from the code in compile time either, since the type is given by the programmer. Actually C# is completely statistically typed up to C# 4.0 were some dynamic typing was added which will be discussed in the next posts. Starting from C# 3.0 some implicit typing was added to the language as well due to LINQ(with the keyword var). In these types of scenarios, although the explicit type is not mentioned by the programmer, the compiler still infers the type at compile type and we still have compile time type checking. 
Type safety is a very interesting issue. For example in C++ we have all sorts of freedom when dealing with types. We can cast any type to another and the C++ compiler would not complain. For example we can cast a char* to a int* and then with a dereference operator we'll be able to get a number out of the four first bytes of the string ! (with 32 bit integers and little-endian architecture). This of course gives us all sorts of flexibility in our code. But this flexibility also adds quite a lot of rope to hang ourselves with. In C#, this is no longer a case since C# is type safe. Meaning that although you can have type conversions using casting only those compatible conversions are allowed. 
If we define strongly typed languages as those who don't allow any type conversions then C# definitely is not strongly typed. With allowing implicit type conversions certain complex scenarios develop which create the need for runtime type checking. A very interesting example of this is the result of array covariance. Arrays are reference types and implicit casting from an array to another is allowed as long as the elements in the array are convertible. This however does not mean that the language doesn't check for proper covariance:

   
    string[] strArray = new string[10];
    object[] objArray = strArray;
    objArray[0] = new Button();

In the above example we have defined and array of type string and then assigned it by reference to the object array. This requires an implicit cast and type check in compile time. This means that the compiler checks to see if the type of strArray or its elements are compatible with objArray or their elements. If that is the case this conversion is allowed(covariance), otherwise a compile error is thrown. Now, in the next line we try to assign a Button to an element in the object array. This is perfectly legal as long as the compiler is concerned. Since the object array can hold elements of type object. Notice that the compiler cannot know what the actual object array is referencing until runtime. This would result in a runtime error. The reason for that is the fact that both objArray and strArray are referencing the same array of strings. Although objArray is allowed to reference that array it cannot change the type of the array since the type is statically set to string. Consequently, the runtime knowing the type of the array disallows an operation to store anything other than strings in that position.

No comments:

Post a Comment