|Written by Mike James|
|Tuesday, 11 March 2014|
Page 1 of 4
What exactly is C#'s dynamic type all about? Is it dynamic or is it just static typing under cover? And how does it change things like early binding, virtual and non-virtual?
C# is a language that started out in the style of Java with strong typing and very little extra. Over time it has added features in a careful and thoughtful way to include things that you might not associate with a strongly typed "traditional" object oriented language. For many this is what makes C# special.
Back in version, 4.0, it added the unthinkable - late binding with dynamic typing. This provides the modern C# programmer with idioms that previously would have been thought out of the question. Dynamic typing goes directly against static strong typing that is supposed to catch so many errors are compile time that otherwise would only appear at run time.
The worry is that by adopting such loose practice C# might become a mess by adopting models that go against its birthright of strict typing and object-oriented procedural code?
What is interesting is the way that C# combines the best of both worlds - but see if you agree.
On being dynamic in C#
Strong typing isn't necessarily the good idea it first seems to be - it has some advantages but so does dynamic typing.
It is also true that it is the biggest current divide between programmers and programming languages is into camps that swear allegiance to the strong typing principle or simply attempt to ignore type altogether because it is simpler.
C# started out as a young, clean, strongly-typed language but as it reaches its middle age it is displaying signs of being envious of the currently popular dynamic languages. This is made worse by the desire to meet the demand to be simpler, easier to use and more productive.
First it is worth saying what strict, static and dynamic typing are all about.
A language uses strict typing if it demands that every item of data has a type and can only be stored in a variable of that type.
Usually things are a little more complicated in that types form a hierarchy and a variable of a given type can store data of that type and types derived from it. Put simply a strictly typed language "worries" about type and generates type exceptions when it thinks you are trying to store data of the wrong type in a variable.
Contrast this with a freely typed language that tries to make it possible for you to store any data in any variable and tries to make sense of what you want to do taking the actual type into account. Put simply a freely typed language tries to ignore data type as much as possible and generates a type exception only when you write something that cannot be reasonably achieved. the type free language motto is "if it can be made to work its ok".
A strongly typed language can also be statically or dynamically typed.
Static typing means that all data types can be worked out at compile time and any errors can be flagged at compile time. In other words you can work out the types of all data and all variables simply by reading the code.
A dynamic language allows a variable to determine its type at run time. In this case you can't necessarily work out the type of a variable by simply reading the code and not all type errors can be picked up at compile time.
Notice that there are two variations possible on dynamic typing. You could enforce a rule which fixes the type of a variable once it is known i.e. variables can't change their type once set. Or you could implement fully dynamic typed variables that can be used to store anything anytime and change there type according to what is stored in them.
You might at this point think that its all very simple but in an object oriented language like C# type actually plays a role in determining what happens in a program - it can change the flow of control and hence things are more subtle.
Before moving on to consider dynamic typing it is worth spending a few minutes considering how static typing works and how it determines the way things work in C#.
First, recall that in C# 2.0 you always had to determine the type of the result of an expression and use an appropriate type or super type to store it and this determination had to be made at compile time.That is C# 2.0 is a statically typed language.
Even now the compiler always looks at an expression, determines the type of the expression and makes sure that this is compatible the "assignment" variable.
Notice that this applies to assignment proper, method parameters and return types. Type determination can also affect the flow of control in a program - but static typing can only determine it at compile time.
For example, consider the two overloaded methods defined within some object:
then when you write:
which method is called depends on the type of X.
If X is an int the first method is called and if it is a double the second method is called.
You may well be used to the idea that overloaded methods are called according to signature but you might not have realised how important this makes the determination of type as part of the flow of control in your program.
The method call MyMethod(X) resolved according to the signature of the call might be thought to be expressed by the equivalent code:
but notice that this code actually determines the type of X at runtime not compile time. If there was some way for X to change to a double before the if MyMethodDouble would be called.
If you examine the code and remember that this is a static language you can see that MyMethodInt is always called - there is no possibility of anything else happening because X is always an int once it has been declared to be an int.
In this sense the whole if statement and testing is completely unnecessary you might as well write:
In a statically typed language there is no way a variable can change the type it is assigned when it is declared.
However even static typing is a little more subtle than this. The extra complexity comes from the idea that any type that derives from another type should be usable in place of the parent type.That is, if I declare a class as:
then MyClass2 can be used in place of MyClass and generally treated as if it was of type MyClass - this is the content of the Liskov substitution principle, a sub-class has all of the properties and methods of its parent class, by inheritance and can therefore be used in place of it.
For example a method like:
can be called with a parameter of type MyClass or MyClass2. So, from the point of view of method signatures, derived classes act like their parent classes. So what if we now overload MyMethod with a specific version for MyClass2?
Now if I call MyMethod with a parameter of type MyClass2 which method will be called?
The answer is, unsurprisingly the one with the signature that matches the parameter most closely. In this case the version of MyMethod with the MyClass2 parameter is called.
This is a general principle: the method with the signature that most closely matches the types used in the signature is used.
|Last Updated ( Tuesday, 11 March 2014 )|