csharp

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.

Some definitions

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.

Static typing

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:

public string MyMethod(int i){
return "Integer";
}
public string MyMethod(double f){
return "Double";
}

then when you write:

MyObject.MyMethod(X);

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:

MyClass MyObject = new MyClass();
int X = 1;
if (X is int)
{
MyObject.MyMethodInt(X);
}
else if (X is double)
{
MyObject.MyMethodDouble(X);
}

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:

int X = 1;
MyObject.MyMethodInt(X);

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:

public class MyClass2:MyClass
{
'''
}

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:

public string MyMethod(MyClass obj) {
return "MyClass";
}

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?

public string MyMethod(MyClass2 o){
return "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.

Although this use of derived types in method calls is a little more complicated notice that it uses the declared type of each variable and not what the variable actually references.

That is which version of the method is called can always be determined at compile time. Another way of saying this is that by default all method calls are early bound.

In fact the only example of late binding in C# occurs when a method is declared to be virtual. In this case the method that is called does depend on runtime type, not of its parameters but on the runtime type of the class it belongs to. That is, if MyMethod isn’t declared as virtual then:

MyObject.MyMethod();

will always call the MyMethod defined as part of what ever type MyObject is declared to be. In other words, you can read through the program’s code until you find:

MyClass MyObject=New MyClass();

and then without examining the program any further you can conclude with 100% certainty that the version of MyMethod that will be called is the one defined as part of MyClass – even if MyMethod has been overridden in a class derived from MyClass.

That is if MyMethod isn’t virtual then (notice that the variable is of type MyClass but the object it references is MyClass2:

MyClass MyObject=New MyClass2();
MyObject.MyMethod();

still calls the appropriate version of MyMethod defined as part of MyClass not any alternative defined in MyClass2. This is once again early binding as the method call is determined at compile time. That is the variable MyObject is of type MyClass so it is the MyClass version of MyMethod that is called no matter what MyClass2 does to it.

If, on the other hand, MyMethod is declared as virtual in MyClass and overriden correctly in MyClass2 then in this case late binding operates and:

MyClass MyObject=New MyClass2();
MyObject.MyMethod();

does call the new version of MyMethod as defined as part of MyClass2.

This is what the whole virtual/non-virtual distinction is about. All non-virtual methods are early bound according to the type of the variable holding the reference to the object but virtual methods are late bound according to the type of the object the variable references at run time.

So apart from the use of virtual methods all binding in C# is early binding and only the declared type of a variable can influence what a program does.

As we will see dynamic typing promotes the determination of type to something that can determine what happens at runtime beyond the use of virtual.

But before we look at dynamic typing we need to take a look at a related feature that is often confused with dynamic typing – anonymous typing.

Anonymous typing

The most type-free statement you could write in C# 2.0 is something like:

object x = MyFunc();

which works no matter what type MyFunc returns. However, you can’t do anything with the returned object unless you cast it to a more appropriate type.

That is in most object oriented languages the top most class in the hierarchy, usually called object, can be used as a reference to any sub-class and in this sense using it is a way to make the language less type dependent.

In C# 3.0 the anonymous type was introduced as an alternative to using object and the potential confusion began.

An anonymous type is strongly and statically typed in that the compiler works out its type at compile time and then applies all the usual strong typing rules.

The only complication here is that if the type implied by the code doesn’t actually exist as a named type the compiler will also generate a suitable name and type.

That is anonymous typing is still early binding in action and everything that happens is fixed at compile time.

Let’s start off with the simplest anonymous type. For example, given the function:

public int MyFunc() {
return 1;
}

the statement:

var x = MyFunc();

allows the compiler to deduce that the variable must be an int. So after this you can use:

x = 2;

but the statements:

string i;
i = x;

will still result in a compile time type error as x is an int and i is a string. Anonymous types are still strongly typed at runtime and their type is deduced at compile time i.e. they are static types that the compiler infers from the static code.

A slightly more complicated situation is where the type is created “on the fly”:

var x = new {
name = "Mike",
Address = "AnyTown"
};

In this case the new type doesn’t have a name and so the compiler creates one something along the lines of “AnonymousType#1”.

Now you can use statements like:

string i;
i = x.name;

as not only has the type of the structure been determined so has the type of each of its fields.

A subtle point that is important not to miss is that an anonymous type created in this way is read-only so you can’t assign to any of its fields and any attempts to do so will be picked up by the compiler.

Notice that this is different from the behaviour when the inferred type already exists when the type is, unless, of course, the type is otherwise restricted to be read only.

For example, if you first declare the structure previously created on the fly:

public struct MyAdd {
public string name;
public string Address;
}

and change the function to read:

public MyAdd MyFunc(){
return new MyAdd {
name = "Mike",
Address = "MyTown"
};
}

then you can write:

string i;
var x = MyFunc();
x.name="new name";
i = x.name;

If you need even more proof that an anonymous type is strongly typed just notice the fact that the type and its fields are included in Intellisense prompting as you work with the code at design time!

It really is that simple. If you declare two anonymous types that have an identical field structure then the compiler is smart enough to notice that it needs to create only a single new type name but as the resulting objects are read-only you still can’t use assignment.

There are some restrictions on how you can use anonymously typed variables but they are all fairly obvious and reasonable.

In particular the anonymous variable has to be local, i.e have method scope. This means that you can still use them within for, foreach and using statements.

Of course it has to be mentioned that anonymous types were introduced mainly to make LINQ look easier to use – but you can still use LINQ, and indeed everything in C#, without ever using the var statement.

Anonymous types are entirely a convenience and in no way a necessity as if the compiler can deduce the type of a variable at compile time – so can you!

Dynamic typing

The other end of the spectrum from or static typing is dynamic typing. In true dynamic typing a variable really can change its type at runtime.

This this doesn’t have to be the abandonment of type checking just a move to type checking at run rather than compile time. C# hasn’t quite adopted the “duck typing” approach that makes languages such as JavaScript, Ruby and Python, as it is still attempting to play within the strong typing rules it started out with.

 

 

The best way of thinking about dynamic type is as a sort of formal way to use a general object type which which allows you access to the methods and properties of the actual data type in use without the need to cast.

For example, suppose we have a class:

public class MyClass {
public int MyProperty;
public int MyMethod() {
return 1;
}
}

If we now create an instance using an object reference type:

object MyObject = new MyClass();

then trying to access any of the methods or properties of the object will fail for obvious reasons – an object type doesn’t have the methods and properties of a MyClass type.

However, if you use a cast to MyClass then you can access all of the properties and methods as if MyObject was of type MyClass that is:

((MyClass) MyObject).MyMethod();

works perfectly.

In this sense using object and cast has long been the C# programmer’s way of implementing dynamic typing. In this sense dynamic typing is nothing new to the language.

However you must have had the thought

“why do I need to cast the object to the correct type – either the method call works or doesn’t work at run-time”. 

Apart from making it easier to discover the programmer’s intention the cast does absolutely nothing to protect you from an error at compile time – any problems only become apparent at runtime.

With the new dynamic type you can indeed “drop the cast”.

The same code in C# can be written using the dynamic type introduced in version 4.0:

dynamic MyObject = new MyClass();
MyObject.MyMethod();

The dynamic type only resolves to a method or property at runtime.

Interestingly you can mix dynamic and anonymous as in:

dynamic MyObject = new MyClass();
var i=MyObject.MyMethod();

and the compiler correctly works out that i should be an int – suggesting that it isn’t completely blind to the type stored in MyObject. Notice that as dynamic is a valid static type name it is perfectly possible that an anonymous type will resolve to dynamic.

You can swap from dynamic to fully static simply by making appropriate assignments. For example:

dynamic j = 1;
int i = j;

first creates a dynamic variable, an int, which is then converted to a strongly typed int. You can also force a conversion using a cast but, as always, if it can’t be done the result is a runtime exception.

Notice that dynamic really is dynamic in the sense that the determination of its type at runtime isn’t a one off. A dynamic type can change its type as many times as necessary. For example:

dynamic i;
i = 1;
i = i + 1;
i = "mike";
i = i + 1;

When the int 1 is assigned to it i becomes an int, and i+1 is an integer expression which evaluates to 2. Assigning the string “mike” to i changes its runtime type to string and now i+1 concatenates the string “1” which is implicitly cast from an int to give “mike1”.

Notice that there is nothing new going on here as every thing works just as it would if the variable i was first declared as an int and then declared as a string – of course you can’t change the type of a static type at compile time.

The guiding principle that has been used in implementing the dynamic type is that what happens should correspond to what happens if the dynamic type was known at compile rather than runtime.

So to work out how a dynamic type behaves simply imagine that you know its type at compile time and what happens in this case should be what happens to the dynamic type.

Late or early?

Whenever you change something in a language, no matter how small or innocent the change is, the ripples spread out and reach parts of the language that you might never have guessed at.

For example, with dynamic typing late binding is the rule even if the method in use isn’t virtual. Consider the following class with two overloaded versions of the same method:

public class MyClass {
public string MyMethod(int i){
return "Integer";
}
public string MyMethod(double f){
return "Double"; }
}

If we now call the method but with a random type, i.e. a the type of the object is selected randomly, something that was impossible to do before the introduction of dynamic, as in:

Random R = new Random();
MyClass MyObject = new MyClass();
dynamic i;
if(R.NextDouble()<.5){
i = 1;
}else{
i=1.0;
}
string result=MyObject.MyMethod(i);

then which MyMethod is actually called is determined at run time according to the type of i which is discovered using reflection. If i is a double then MyMethod(double f) is called and if it i is an int then MyMethod(int i) is called.

This should be the behaviour you expect from your understanding of the way that dynamic types work but notice that this means that the late binding is being used in a situation where you might have expected the usual early binding. That is, it fits into the principle that what should happen should be the same as if the type of the dynamic variable was known at compile time.

Overloading And Overriding

This can be slightly more complicated in that we can mix method overloading with overriding in a derived class – but the guiding principle still applies.

For example, suppose we have a derived class which overrides a non-virtual  method in the original MyClass:

public class MyClass2:MyClass{
public new string MyMethod(double f){
return "Class2 Double";
}
}

As the method isn’t virtual you would expect early binding to be used i.e. based on the compile type type of the object. However we have already noted that using a dynamic parameter forces late binding. So which is it?

That is of we now change the creation of MyObject in the previous example to read:

MyClass MyObject = new MyClass2();

which method will be used for a double MyClass’s or MyClass2’s?

At compile time the type of MyObject is MyClass even if at run time it actually refers to a MyClass2 object and so by the usual early binding rules it should be MyClass’s methods that are used and indeed this is what happens – even though which MyClass method is called isn’t determined until runtime.

Thus the method call is early bound to the class type but late bound according to the signature of the call.

However,  if you change the method declarations to virtual and override late binding is used on them both and MyClass2’s double method is called

This is ruthlessly logical and if you stop to think about it what really should happen in each case.

There are a number of other interesting but fairly esoteric “features” of dynamic but one final one worth mentioning is accessibility.

Currently all methods and properties have to be public to be dynamically accessible. This isn’t a huge problem but it means that you can’t call private methods from within a class using dynamic parameters even though without the dynamic parameters the call would be perfectly legal.

Similarly you can’t use extension methods dynamically – the information to implement them isn’t available at run time. Anonymous functions can’t appear as arguments to a dynamic method call for the same reason. This makes it difficult to use LINQ queries over dynamic objects, which is strange given that LINQ was and is a major motivation for C# becoming more dynamic.

Beyond plain .NET objects

How the method invocation or property access is handled depends on the type of object that the dynamic type references.

You might think that the only possibility is the plain old .NET object but part of the reason for introducing dynamic is to make externally derived objects easier to work with.

In the case of a standard .NET object reflection is used to dispatch the operation. This is more sophisticated than you might imagine because any dynamic objects passed as parameters are resolved using reflection and then the resulting signature combined with reflection is used to make call to the appropriate method.

Moving beyond plain .NET objects a new class of dynamic objects can customise how they behave by implementing the IDynamicObject interface.

In this case the task of working out which method or property is needed is handed off to the object itself to work out using any method that suits. This is the key to building truly dynamic object models that can respond in sophisticated ways.

A very big advantage of dynamic types comes when you start to think about C#’s relationship with external and non-native objects – COM objects in particular. In this case a dynamic type is resolved using the COM IDispatch interface and this in turn means that you can use COM objects “raw”, i.e. without a Primary Interop Assembly (PIA).

As many COM objects make extensive use of the variant type, which can store any of a number of standard data types, being able to use dynamic types in place of variants is a big simplification.

For example, consider the standard difficulty encountered in using the Office COM object model:

((Excel.Range)excel.Cells[1,1]).
Value= “some string”

The cast has to be included because the PIA uses object types to represent variants. Using dynamic types in place of objects makes it possible to dispense with the cast and allow the run time system to work out what is legal:

excel.Cells[1,1].Value= “some string”

Not using the PIA and driving the COM interface raw also means that you can hope to achieve a more efficient and lightweight program.

There are other minor enhancements to the way COM objects are dealt with in introduced in C# 4.0 that go together with dynamic types to make the whole thing easier to use.

For example, COM objects often pass parameters using pointers which result in the use of ref parameters in the corresponding C# methods. This can force you to create temporary variables to avoid any changes to a variable that you regard as logically being passed by value. Now the compiler will do the job for you by converting the value parameter to a temporary copy and passing this by reference.

The overall result is pass-by-value semantics for parameters that are passed as pointers.

Verdict

Dynamic typing seems to be mostly harmless and it does improve the way that you can write some things that rely on determining type at runtime rather than compile time but it is a big change. It doesn’t go as far as introducing a true dynamic approach to type but it is a change in philosophy.

Even if you regard it as an attempt to work with other systems that are less strict about type it is still a change that makes C# less pure and more ad-hoc.

Source : i-programmer

Leave a Reply

Your email address will not be published. Required fields are marked *